diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index da96ae6b..87d8dd6f 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -7,6 +7,8 @@ + + Main UIRequiresFullScreen + NSFaceIDUsageDescription + Why is my app authenticating using face id? UISupportedInterfaceOrientations UIInterfaceOrientationPortrait diff --git a/lib/app_state.dart b/lib/app_state.dart index bfc93a71..0b79b097 100644 --- a/lib/app_state.dart +++ b/lib/app_state.dart @@ -1,9 +1,67 @@ +import 'dart:ffi'; + +import 'package:f_r_e_hub/flutter_flow/permissions_util.dart'; import 'package:flutter/material.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:csv/csv.dart'; +import 'package:local_auth/local_auth.dart'; +import 'package:permission_handler/permission_handler.dart'; import 'package:synchronized/synchronized.dart'; class FFAppState extends ChangeNotifier { + // Adiciona a variável para controle de autenticação biométrica + bool _isBiometricAuthenticated = false; + bool get isBiometricAuthenticated => _isBiometricAuthenticated; + + // Instância do LocalAuthentication + final LocalAuthentication auth = LocalAuthentication(); + + // Verifica suporte biométrico + Future checkBiometrics() async { + try { + return await auth.canCheckBiometrics; + } catch (e) { + clearBiometricAuthentication(); + debugPrint('Error checking biometrics: $e'); + return false; + } + } + + // Solicita autenticação biométrica + Future authenticateBiometric() async { + bool authenticated = false; + try { + authenticated = await auth.authenticate( + localizedReason: 'Scan your fingerprint to authenticate', + options: const AuthenticationOptions( + biometricOnly: true, + stickyAuth: true, + useErrorDialogs: true, + sensitiveTransaction: true, + ) + ); + if (authenticated) { + _isBiometricAuthenticated = true; + notifyListeners(); + // Salvar o estado de autenticação biométrica, se necessário + } + } catch (e) { + print(e); + debugPrint('Error authenticating: $e'); + clearBiometricAuthentication(); + } + } + + // Função para limpar o estado de autenticação biométrica + void clearBiometricAuthentication() { + _isBiometricAuthenticated = false; + notifyListeners(); + // Limpar a informação salva, se necessário + } + + + + static FFAppState _instance = FFAppState._internal(); factory FFAppState() { @@ -69,6 +127,25 @@ class FFAppState extends ChangeNotifier { await _safeInitAsync(() async { _serialNumber = await secureStorage.getString('ff_serialNumber') ?? _serialNumber; }); + await _safeInitAsync(() async { + _fingerprintOPT = await secureStorage.getBool('fingerprint') ?? _fingerprintOPT; + }); + await _safeInitAsync(() async { + _personOPT = await secureStorage.getBool('person') ?? _personOPT; + }); + await _safeInitAsync(() async { + _passOPT = await secureStorage.getBool('pass') ?? _passOPT; + }); + await _safeInitAsync(() async { + _notifyOPT = await secureStorage.getBool('notify') ?? _notifyOPT; + }); + await _safeInitAsync(() async { + _accessPass = await secureStorage.getString('accessPass') ?? _accessPass; + }); + await _safeInitAsync(() async { + _panicPass = await secureStorage.getString('panicPass') ?? _panicPass; + }); + } void update(VoidCallback callback) { @@ -78,6 +155,70 @@ class FFAppState extends ChangeNotifier { late FlutterSecureStorage secureStorage; + String _accessPass = ''; + String get accessPass => _accessPass; + set accessPass(String value) { + _accessPass = value; + secureStorage.setString('accessPass', value); + } + + void deleteAccessPass() { + secureStorage.delete(key: 'accessPass'); + } + + String _panicPass = ''; + String get panicPass => _panicPass; + set panicPass(String value) { + _panicPass = value; + secureStorage.setString + ('panicPass', value); + } + + void deletePanicPass() { + secureStorage.delete(key: 'panicPass'); + } + + bool _notifyOPT = false; + bool get notify => _notifyOPT; + set notify(bool value) { + _notifyOPT = value; + secureStorage.setBool('notify', value); + } + + bool _passOPT = false; + bool get pass => _passOPT; + set pass(bool value) { + _passOPT = + value; + secureStorage.setBool('pass', value); + } + + void deletePass() { + secureStorage.delete(key: 'pass'); + } + + bool _personOPT = false; + bool get person => _personOPT; + set person(bool value) { + _personOPT = value; + secureStorage.setBool('person', value); + } + + void deletePerson() { + secureStorage.delete(key: 'person'); + } + + bool _fingerprintOPT = false; + bool get fingerprint => _fingerprintOPT; + set fingerprint(bool value) { + _fingerprintOPT = value; + secureStorage.setBool('fingerprint', value); + } + + void deleteFingerprint() { + secureStorage.delete(key: 'fingerprint'); + } + String _serialNumber = ''; String get serialNumber => _serialNumber; set serialNumber(String value) { @@ -270,6 +411,10 @@ class FFAppState extends ChangeNotifier { void deleteName() { secureStorage.delete(key: 'ff_name'); } + + void deleteAll() { + secureStorage.deleteAll(); + } } void _safeInit(Function() initializeField) { diff --git a/lib/backend/api_requests/api_calls.dart b/lib/backend/api_requests/api_calls.dart index 0f820e03..3b8fe216 100644 --- a/lib/backend/api_requests/api_calls.dart +++ b/lib/backend/api_requests/api_calls.dart @@ -41,8 +41,125 @@ class PhpGroup { static GetLiberationsCopyCall getLiberationsCopyCall = GetLiberationsCopyCall(); static GetMessagesCall getMessagesCall = GetMessagesCall(); + static ChangeNotifica changeNotifica = ChangeNotifica(); + static RespondeVinculo resopndeVinculo = RespondeVinculo(); + static ChangePass changePass = ChangePass(); } +class ChangePass { + Future call({ + String? devUUID = '', + String? userUUID = '', + String? cliID = '', + String? atividade = '', + String? newSenha = '', + }) async { + final baseUrl = PhpGroup.getBaseUrl(); + + return ApiManager.instance.makeApiCall( + callName: 'changePass', + apiUrl: '$baseUrl/processRequest.php', + callType: ApiCallType.POST, + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + params: { + 'devUUID': devUUID, + 'userUUID': userUUID, + 'cliID': cliID, + 'atividade': atividade, + 'newSenha': newSenha, + }, + bodyType: BodyType.X_WWW_FORM_URL_ENCODED, + returnBody: true, + encodeBodyUtf8: false, + decodeUtf8: false, + cache: false, + isStreamingApi: false, + alwaysAllowBody: false, + ); + } + + bool? error(dynamic response) => castToType(getJsonField( + response, + r'''$.error''', + )); +} + +class RespondeVinculo { + Future call({ + String? devUUID = '', + String? userUUID = '', + String? cliID = '', + String? tarefa = '', + }) async { + final baseUrl = PhpGroup.getBaseUrl(); + + return ApiManager.instance.makeApiCall( + callName: 'respondeVinculo', + apiUrl: '$baseUrl/processRequest.php', + callType: ApiCallType.POST, + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + params: { + 'devUUID': devUUID, + 'userUUID': userUUID, + 'cliID': cliID, + 'tarefa': tarefa, + }, + bodyType: BodyType.X_WWW_FORM_URL_ENCODED, + returnBody: true, + encodeBodyUtf8: false, + decodeUtf8: false, + cache: false, + isStreamingApi: false, + alwaysAllowBody: false, + ); + } + +} + +class ChangeNotifica { + Future call({ + String? devUUID = '', + String? userUUID = '', + String? cliID = '', + String? atividade = '', + String? notifica = '', + }) async { + final baseUrl = PhpGroup.getBaseUrl(); + + return ApiManager.instance.makeApiCall( + callName: 'changeNotifica', + apiUrl: '$baseUrl/processRequest.php', + callType: ApiCallType.POST, + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + params: { + 'devUUID': devUUID, + 'userUUID': userUUID, + 'cliID': cliID, + 'atividade': atividade, + 'notifica': notifica, + }, + bodyType: BodyType.X_WWW_FORM_URL_ENCODED, + returnBody: true, + encodeBodyUtf8: false, + decodeUtf8: false, + cache: false, + isStreamingApi: false, + alwaysAllowBody: false, + ); + } + + bool? error(dynamic response) => castToType(getJsonField( + response, + r'''$.error''', + )); +} + class UpdToken { Future call({ String? token = '', diff --git a/lib/components/molecular_components/message_opt_modal/opt_modal_model.dart b/lib/components/molecular_components/message_opt_modal/opt_modal_model.dart new file mode 100644 index 00000000..51674c2a --- /dev/null +++ b/lib/components/molecular_components/message_opt_modal/opt_modal_model.dart @@ -0,0 +1,31 @@ +import '/flutter_flow/flutter_flow_util.dart'; +import '/flutter_flow/form_field_controller.dart'; +import 'opt_modal_widget.dart' show OptModalWidget; +import 'package:flutter/material.dart'; + +class OptModalModel extends FlutterFlowModel { + /// State fields for stateful widgets in this component. + + // State field(s) for TextField widget. + FocusNode? textFieldFocusNode; + TextEditingController? textController; + String? Function(BuildContext, String?)? textControllerValidator; + // State field(s) for Checkbox widget. + bool? checkboxValue1; + // State field(s) for Checkbox widget. + bool? checkboxValue2; + // State field(s) for CheckboxGroup widget. + FormFieldController>? checkboxGroupValueController; + List? get checkboxGroupValues => checkboxGroupValueController?.value; + set checkboxGroupValues(List? v) => + checkboxGroupValueController?.value = v; + + @override + void initState(BuildContext context) {} + + @override + void dispose() { + textFieldFocusNode?.dispose(); + textController?.dispose(); + } +} diff --git a/lib/components/molecular_components/message_opt_modal/opt_modal_widget.dart b/lib/components/molecular_components/message_opt_modal/opt_modal_widget.dart new file mode 100644 index 00000000..551004ef --- /dev/null +++ b/lib/components/molecular_components/message_opt_modal/opt_modal_widget.dart @@ -0,0 +1,330 @@ +import 'package:f_r_e_hub/components/molecular_components/opt_modal/opt_modal_model.dart'; +import 'package:f_r_e_hub/flutter_flow/flutter_flow_theme.dart'; +import 'package:f_r_e_hub/flutter_flow/flutter_flow_util.dart'; +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; + +class OptModalWidget extends StatefulWidget { + final String defaultPersonType; + final String defaultAccessType; + + const OptModalWidget({ + Key? key, + this.defaultPersonType = '.*', + this.defaultAccessType = '.*', + }) : super(key: key); + + @override + _OptModalWidgetState createState() => _OptModalWidgetState(); +} + +class _OptModalWidgetState extends State { + late OptModalModel _model; + + late Map selected; + final List> personTypeOptions = [ + {'title': 'zok7lu4w', 'value': 'E'}, + {'title': 'oonqk812', 'value': 'O'}, + ]; + final List> accessTypeOptions = [ + {'title': '580z80ct', 'value': '0'}, + {'title': '1nbwqtzs', 'value': '1'}, + ]; + + @override + void setState(VoidCallback callback) { + super.setState(callback); + _model.onUpdate(); + } + + @override + void initState() { + super.initState(); + + _model = createModel(context, () => OptModalModel()); + + _model.textController ??= TextEditingController(); + _model.textFieldFocusNode ??= FocusNode(); + + selected = { + 'personType': widget.defaultPersonType == '.*' + ? ['E', 'O'] + : [widget.defaultPersonType], + 'accessType': widget.defaultAccessType == '.*' + ? ['0', '1'] + : [widget.defaultAccessType], + 'search': '.*', + }; + } + + void _applyFilter() { + Map filterResult = { + 'personType': '', + 'accessType': '', + 'search': _model.textController.text == '' + ? '.*' + : _model.textController.text.toLowerCase(), + }; + + if (selected['personType']!.isEmpty) { + filterResult['personType'] = '.*'; + } else if (selected['personType']!.length > 1) { + filterResult['personType'] = '.*'; + } else { + filterResult['personType'] = selected['personType']!.first; + } + + if (selected['accessType']!.isEmpty) { + filterResult['accessType'] = '.*'; + } else if (selected['accessType']!.length > 1) { + filterResult['accessType'] = '.*'; + } else { + filterResult['accessType'] = selected['accessType']!.first; + } + + Navigator.pop(context, filterResult); + } + + Widget _buildCheckboxListTile(String key, List> options) { + return Column( + children: [ + Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Padding( + padding: + const EdgeInsetsDirectional.fromSTEB(0.0, 10.0, 0.0, 0.0), + child: Text( + FFLocalizations.of(context).getText('l7tw8b92'), + textAlign: TextAlign + .left, // Adiciona esta linha para alinhar o texto à esquerda + style: FlutterFlowTheme.of(context).bodyMedium.override( + fontFamily: FlutterFlowTheme.of(context).bodyMediumFamily, + letterSpacing: 0.0, + useGoogleFonts: GoogleFonts.asMap().containsKey( + FlutterFlowTheme.of(context).bodyMediumFamily), + color: FlutterFlowTheme.of(context).primaryText, + ), + ), + ), + ], + ), + ListView.builder( + shrinkWrap: true, + itemCount: options.length, + itemBuilder: (context, index) { + final option = options[index]; + return CheckboxListTile( + title: Text( + FFLocalizations.of(context).getText(option['title']!), + style: FlutterFlowTheme.of(context).bodyMedium.override( + fontFamily: FlutterFlowTheme.of(context).bodyMediumFamily, + letterSpacing: 0.0, + useGoogleFonts: GoogleFonts.asMap().containsKey( + FlutterFlowTheme.of(context).bodyMediumFamily), + color: FlutterFlowTheme.of(context).primaryText, + ), + ), + dense: true, + value: selected[key]!.contains(option['value']), + onChanged: (bool? value) { + setState(() { + if (value == true) { + if (!selected[key]!.contains(option['value'])) { + selected[key]!.add(option['value']); + } + } else { + selected[key]!.remove(option['value']); + } + }); + }, + activeColor: FlutterFlowTheme.of(context).primary, + checkColor: FlutterFlowTheme.of(context).info, + checkboxShape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(100), + ), + enableFeedback: true, + side: BorderSide( + width: 10, + color: FlutterFlowTheme.of(context).secondaryText, + ), + controlAffinity: + ListTileControlAffinity.leading, // Adiciona esta linha + ); + }, + ), + ], + ); + } + + void _updateSelection(String? value, String key) { + setState(() { + if (value == '.') { + selected[key] = []; + } else if (value != null) { + if (selected[key]!.contains(value)) { + selected[key]!.remove(value); + } else { + selected[key]!.add(value); + } + } + }); + } + + @override + Widget build(BuildContext context) { + return SafeArea( + child: Align( + alignment: const AlignmentDirectional(1.0, -1.0), + child: Padding( + padding: const EdgeInsetsDirectional.fromSTEB(0.0, 50.0, 50.0, 0.0), + child: Container( + width: 300.0, + height: 450.0, + decoration: BoxDecoration( + color: FlutterFlowTheme.of(context).primaryBackground, + borderRadius: BorderRadius.circular(24.0), + ), + child: Padding( + padding: const EdgeInsets.all(4.0), + child: Column( + children: [ + Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsetsDirectional.fromSTEB( + 10.0, 10.0, 0.0, 10.0), + child: Text( + FFLocalizations.of(context) + .getText('yfj9pd6k'), // Filtros + style: FlutterFlowTheme.of(context) + .headlineMedium + .override( + fontFamily: FlutterFlowTheme.of(context) + .headlineMediumFamily, + color: FlutterFlowTheme.of(context).primaryText, + fontSize: 16.0, + letterSpacing: 0.0, + useGoogleFonts: GoogleFonts.asMap().containsKey( + FlutterFlowTheme.of(context) + .headlineMediumFamily), + ), + ), + ), + ], + ), + Padding( + padding: const EdgeInsetsDirectional.fromSTEB( + 8.0, 0.0, 8.0, 0.0), + child: TextFormField( + controller: _model.textController, + focusNode: _model.textFieldFocusNode, + autofocus: false, + obscureText: false, + decoration: InputDecoration( + isDense: true, + labelText: FFLocalizations.of(context).getText( + '0enrtljz' /* Pesquise aqui..... */, + ), + labelStyle: FlutterFlowTheme.of(context) + .labelMedium + .override( + fontFamily: FlutterFlowTheme.of(context) + .labelMediumFamily, + color: FlutterFlowTheme.of(context).primaryText, + letterSpacing: 0.0, + useGoogleFonts: GoogleFonts.asMap().containsKey( + FlutterFlowTheme.of(context) + .labelMediumFamily), + ), + hintStyle: FlutterFlowTheme.of(context) + .labelMedium + .override( + fontFamily: FlutterFlowTheme.of(context) + .labelMediumFamily, + color: FlutterFlowTheme.of(context).primaryText, + letterSpacing: 0.0, + useGoogleFonts: GoogleFonts.asMap().containsKey( + FlutterFlowTheme.of(context) + .labelMediumFamily), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: FlutterFlowTheme.of(context).alternate, + width: 1, + ), + borderRadius: BorderRadius.circular(8.0), + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: FlutterFlowTheme.of(context).primary, + width: 1, + ), + borderRadius: BorderRadius.circular(8.0), + ), + errorBorder: OutlineInputBorder( + borderSide: BorderSide( + color: FlutterFlowTheme.of(context).error, + width: 1, + ), + borderRadius: BorderRadius.circular(8.0), + ), + focusedErrorBorder: OutlineInputBorder( + borderSide: BorderSide( + color: FlutterFlowTheme.of(context).error, + width: 1, + ), + borderRadius: BorderRadius.circular(8.0), + ), + filled: true, + fillColor: FlutterFlowTheme.of(context).alternate, + suffixIcon: const Icon( + Icons.search_outlined, + ), + ), + style: FlutterFlowTheme.of(context).bodyMedium.override( + fontFamily: + FlutterFlowTheme.of(context).bodyMediumFamily, + letterSpacing: 0.0, + useGoogleFonts: GoogleFonts.asMap().containsKey( + FlutterFlowTheme.of(context).bodyMediumFamily), + ), + validator: + _model.textControllerValidator.asValidator(context), + ), + ), + SingleChildScrollView( + child: Container( + padding: const EdgeInsets.all(20), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + _buildCheckboxListTile( + 'personType', personTypeOptions), + _buildCheckboxListTile( + 'accessType', accessTypeOptions), + ], + ), + ), + ), + ElevatedButton( + onPressed: _applyFilter, + child: + Text(FFLocalizations.of(context).getText('88kshkph')), + style: ElevatedButton.styleFrom( + foregroundColor: FlutterFlowTheme.of(context).info, + backgroundColor: FlutterFlowTheme.of(context).primary, + ), + ), + ], + ), + ), + ), + ), + ), + ); + } +} diff --git a/lib/components/organism_components/menu_component/menu_component_model.dart b/lib/components/organism_components/menu_component/menu_component_model.dart index 9c1fffb0..b6aa80df 100644 --- a/lib/components/organism_components/menu_component/menu_component_model.dart +++ b/lib/components/organism_components/menu_component/menu_component_model.dart @@ -101,9 +101,9 @@ class MenuComponentModel extends FlutterFlowModel { ); } - Future acessHistoryOptAction(BuildContext context) async { + Future preferencesSettings(BuildContext context) async { context.pushNamed( - 'acessHistoryPage', + 'preferencesSettings', extra: { kTransitionInfoKey: const TransitionInfo( hasTransition: true, diff --git a/lib/components/organism_components/menu_component/menu_component_widget.dart b/lib/components/organism_components/menu_component/menu_component_widget.dart index d85510d7..20fca7e9 100644 --- a/lib/components/organism_components/menu_component/menu_component_widget.dart +++ b/lib/components/organism_components/menu_component/menu_component_widget.dart @@ -62,8 +62,8 @@ class _MenuComponentWidgetState extends State { await _model.peopleOnThePropertyAction(context); setState(() {}); }, - acessHistoryOptAction: () async { - await _model.acessHistoryOptAction(context); + preferencesSettings: () async { + await _model.preferencesSettings(context); setState(() {}); }, liberationHistoryOptAction: () async { @@ -98,8 +98,8 @@ class _MenuComponentWidgetState extends State { await _model.peopleOnThePropertyAction(context); setState(() {}); }, - accessHistoryOptAction: () async { - await _model.acessHistoryOptAction(context); + preferencesSettings: () async { + await _model.preferencesSettings(context); setState(() {}); }, liberationHistoryOptAction: () async { diff --git a/lib/components/organism_components/menu_list_view_component/menu_list_view_component_widget.dart b/lib/components/organism_components/menu_list_view_component/menu_list_view_component_widget.dart index 2c929518..06154b38 100644 --- a/lib/components/organism_components/menu_list_view_component/menu_list_view_component_widget.dart +++ b/lib/components/organism_components/menu_list_view_component/menu_list_view_component_widget.dart @@ -16,7 +16,7 @@ class MenuListViewComponentWidget extends StatefulWidget { required this.registerVisitorOptAction, required this.scheduleVisitOptAction, required this.peopleOnThePropertyOptAction, - required this.acessHistoryOptAction, + required this.preferencesSettings, required this.liberationHistoryOptAction, required this.accessQRCodeOptAction, }); @@ -25,7 +25,7 @@ class MenuListViewComponentWidget extends StatefulWidget { final Future Function()? registerVisitorOptAction; final Future Function()? scheduleVisitOptAction; final Future Function()? peopleOnThePropertyOptAction; - final Future Function()? acessHistoryOptAction; + final Future Function()? preferencesSettings; final Future Function()? liberationHistoryOptAction; final Future Function()? accessQRCodeOptAction; @@ -876,7 +876,7 @@ Propriedade */ hoverColor: Colors.transparent, highlightColor: Colors.transparent, onTap: () async { - await widget.acessHistoryOptAction?.call(); + await widget.preferencesSettings?.call(); }, child: Container( width: 100.0, @@ -931,7 +931,7 @@ Propriedade */ alignment: const AlignmentDirectional(0.0, 0.0), child: Icon( - Icons.history_sharp, + Icons.settings, color: FlutterFlowTheme.of(context) .accent1, size: 24.0, @@ -953,8 +953,8 @@ Propriedade */ alignment: const AlignmentDirectional(0.0, 0.0), child: Text( FFLocalizations.of(context).getVariableText( - enText: 'Consult\nHistories', - ptText: 'Consultar\nHistóricos', + enText: 'Preferences\nSystem', + ptText: 'Preferências\ndo Sistema', ), style: FlutterFlowTheme.of(context) .titleLarge @@ -979,6 +979,7 @@ Propriedade */ ), ), ), + ].divide(const SizedBox(width: 15.0)), ), ), diff --git a/lib/components/organism_components/menu_staggered_view_component/menu_staggered_view_component_widget.dart b/lib/components/organism_components/menu_staggered_view_component/menu_staggered_view_component_widget.dart index 0853201e..8e5441a3 100644 --- a/lib/components/organism_components/menu_staggered_view_component/menu_staggered_view_component_widget.dart +++ b/lib/components/organism_components/menu_staggered_view_component/menu_staggered_view_component_widget.dart @@ -18,7 +18,7 @@ class MenuStaggeredViewComponentWidget extends StatefulWidget { required this.registerVisitorOptAction, required this.scheduleVisitOptAction, required this.peopleOnThePropertyOptAction, - required this.accessHistoryOptAction, + required this.preferencesSettings, required this.liberationHistoryOptAction, required this.accessQRCodeOptAction, }); @@ -27,7 +27,7 @@ class MenuStaggeredViewComponentWidget extends StatefulWidget { final Future Function()? registerVisitorOptAction; final Future Function()? scheduleVisitOptAction; final Future Function()? peopleOnThePropertyOptAction; - final Future Function()? accessHistoryOptAction; + final Future Function()? preferencesSettings; final Future Function()? liberationHistoryOptAction; final Future Function()? accessQRCodeOptAction; @@ -85,7 +85,7 @@ class _MenuStaggeredViewComponentWidgetState ), crossAxisSpacing: 10.0, mainAxisSpacing: 10.0, - itemCount: 7, + itemCount: 8, padding: const EdgeInsets.fromLTRB( 0, 10.0, @@ -900,6 +900,126 @@ Propriedade */ ), ), ), + () => InkWell( + splashColor: Colors.transparent, + focusColor: Colors.transparent, + hoverColor: Colors.transparent, + highlightColor: Colors.transparent, + onTap: () async { + await widget.preferencesSettings?.call(); + }, + child: Container( + width: 100.0, + height: 100.0, + decoration: BoxDecoration( + color: + FlutterFlowTheme.of(context).primaryBackground, + boxShadow: [ + BoxShadow( + blurRadius: 4.0, + color: + FlutterFlowTheme.of(context).customColor5, + offset: const Offset( + 0.0, + 2.0, + ), + ) + ], + borderRadius: BorderRadius.circular(24.0), + shape: BoxShape.rectangle, + border: Border.all( + color: FlutterFlowTheme.of(context).alternate, + width: 0.5, + ), + ), + child: Padding( + padding: const EdgeInsets.all(4.0), + child: Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Align( + alignment: + const AlignmentDirectional(0.0, 0.0), + child: Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Expanded( + child: Align( + alignment: const AlignmentDirectional( + -1.0, 0.0), + child: Padding( + padding: const EdgeInsetsDirectional + .fromSTEB(8.0, 0.0, 0.0, 0.0), + child: Container( + width: 30.0, + height: 30.0, + decoration: BoxDecoration( + color: + FlutterFlowTheme.of(context) + .primaryBackground, + shape: BoxShape.circle, + ), + alignment: + const AlignmentDirectional( + 0.0, 0.0), + child: Icon( + Icons.history_sharp, + color: + FlutterFlowTheme.of(context) + .accent1, + size: 24.0, + ), + ), + ), + ), + ), + ], + ), + ), + Align( + alignment: + const AlignmentDirectional(0.0, 0.0), + child: Row( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Align( + alignment: const AlignmentDirectional( + 0.0, 0.0), + child: Text( + FFLocalizations.of(context) + .getVariableText( + enText: 'Preferences\nSettings', + ptText: 'Preferências\ndo Sistema', + ), + style: FlutterFlowTheme.of(context) + .titleLarge + .override( + fontFamily: 'Nunito', + color: + FlutterFlowTheme.of(context) + .primaryText, + fontSize: 14.0, + letterSpacing: 0.0, + fontWeight: FontWeight.w500, + useGoogleFonts: + GoogleFonts.asMap() + .containsKey('Nunito'), + ), + ), + ), + ], + ), + ), + ].divide(const SizedBox(height: 0.0)), + ), + ), + ), + ), + ][index](); }, ), diff --git a/lib/components/organism_components/message_well_component/message_well_component_widget.dart b/lib/components/organism_components/message_well_component/message_well_component_widget.dart index 4d3170a0..1a82d88f 100644 --- a/lib/components/organism_components/message_well_component/message_well_component_widget.dart +++ b/lib/components/organism_components/message_well_component/message_well_component_widget.dart @@ -1,13 +1,22 @@ +import 'dart:async'; +import 'dart:collection'; import 'dart:developer'; import 'package:f_r_e_hub/app_state.dart'; import 'package:f_r_e_hub/backend/api_requests/api_calls.dart'; import 'package:f_r_e_hub/flutter_flow/flutter_flow_theme.dart'; -import 'package:f_r_e_hub/flutter_flow/internationalization.dart'; +import 'package:f_r_e_hub/flutter_flow/flutter_flow_util.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:google_fonts/google_fonts.dart'; import 'package:provider/provider.dart'; +import 'package:rxdart/rxdart.dart'; + +final dropdown = BehaviorSubject>.seeded( + LinkedHashMap.from({ + 'All': 'A', + }), +); class MessageWellComponentWidget extends StatefulWidget { const MessageWellComponentWidget({super.key}); @@ -19,29 +28,29 @@ class MessageWellComponentWidget extends StatefulWidget { class _MessageWellComponentWidgetState extends State { - late ScrollController _listViewController; - late VoidCallback _scrollListener; - final dropdownValueNotifier = ValueNotifier('All'); + StreamSubscription? _dropdownSubscription; @override void initState() { super.initState(); - _listViewController = ScrollController(); - _scrollListener = MessageWellNotifier()._scrollListener; - _listViewController.addListener(_scrollListener); + WidgetsBinding.instance?.addPostFrameCallback((_) { + context.read().fetchMessages(); + }); + + _dropdownSubscription = dropdown.stream.listen((_) { + context.read().fetchMessages(); + }); } @override void dispose() { - _listViewController.dispose(); + _dropdownSubscription?.cancel(); super.dispose(); } @override Widget build(BuildContext context) { - final state = context.watch(); - final messages = state.getMessages(); - final theme = FlutterFlowTheme.of(context); + final messages = context.read().getMessages(); return Align( alignment: Alignment.center, child: Padding( @@ -50,21 +59,17 @@ class _MessageWellComponentWidgetState height: MediaQuery.of(context).size.height * 0.8, child: Column( children: [ - _buildHandleMessageWell(context, theme), - _buildMenuMessageWell(context, theme, dropdownValueNotifier), + _buildHandleMessageWell(context, FlutterFlowTheme.of(context)), + _buildMenuMessageWell(context, FlutterFlowTheme.of(context)), Expanded( - child: NotificationListener( - onNotification: _buildScrollMessageListManager, - child: ListView.builder( - controller: _listViewController, - itemCount: messages.length, - shrinkWrap: true, - physics: const AlwaysScrollableScrollPhysics(), - itemBuilder: (context, index) { - var message = messages[index]; - return _buildMessageItem(context, message, index); - }, - ), + child: ListView.builder( + itemCount: messages.length, + shrinkWrap: true, + physics: const AlwaysScrollableScrollPhysics(), + itemBuilder: (context, index) { + var message = messages[index]; + return _buildMessageItem(context, message, index); + }, ), ), ], @@ -74,44 +79,61 @@ class _MessageWellComponentWidgetState ); } - bool _buildScrollMessageListManager(ScrollNotification notification) { - final notifier = context.read(); - if (notification is ScrollUpdateNotification) { - log('Scrolling ...'); - if (_listViewController.offset <= 0 && notification.scrollDelta! < 0) { - log('Scrolling up ...'); - setState(() {}); - } else { - log('Scrolling down ...'); - if (_listViewController.position.extentAfter == 0) { - log('Reached end of list. Incrementing pageNumber...'); - notifier.incrementPageNumber(); - } - setState(() {}); - } - } - return true; - } - - Widget _buildMenuMessageWell(BuildContext context, FlutterFlowTheme theme, - ValueNotifier dropdownValueNotifier) { - final locations = FFLocalizations.of(context); - final all = locations.getVariableText(enText: 'All', ptText: 'All'); - final personal = - locations.getVariableText(enText: 'Personal', ptText: 'Pessoal'); - final global = locations.getVariableText(enText: 'Global', ptText: 'Global'); + Widget _buildMenuMessageWell(BuildContext context, FlutterFlowTheme theme) { + final dropdownItems = LinkedHashMap.from({ + 'All': 'A', + 'Personal': 'O', + 'Global': 'C', + }); return SizedBox( key: UniqueKey(), width: 200, height: 40, - child: ValueListenableBuilder( - valueListenable: dropdownValueNotifier, - builder: (context, value, child) { + child: StreamBuilder( + stream: dropdown.stream.map((event) => event.keys.first), + builder: (context, snapshot) { + final value = snapshot.data; return DropdownButtonFormField( value: value, decoration: InputDecoration( - contentPadding: EdgeInsets.symmetric(horizontal: 10.0), + isDense: true, + contentPadding: const EdgeInsets.symmetric(horizontal: 10.0), + errorBorder: OutlineInputBorder( + borderSide: BorderSide( + color: theme.error, + width: 2, + ), + borderRadius: BorderRadius.circular(10), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: theme.primary, + width: 2, + ), + borderRadius: BorderRadius.circular(10), + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: theme.primary, + width: 2, + ), + borderRadius: BorderRadius.circular(10), + ), + disabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: theme.primary, + width: 2, + ), + borderRadius: BorderRadius.circular(10), + ), + focusedErrorBorder: OutlineInputBorder( + borderSide: BorderSide( + color: theme.error, + width: 2, + ), + borderRadius: BorderRadius.circular(10), + ), border: OutlineInputBorder( borderSide: BorderSide( color: theme.primary, @@ -123,20 +145,16 @@ class _MessageWellComponentWidgetState fillColor: theme.primary, ), onChanged: (String? newValue) { - if (newValue != null) { - dropdownValueNotifier.value = newValue; - } + safeSetState(() => dropdown.value = LinkedHashMap.from({newValue!: dropdownItems[newValue].toString()})); }, - items: [ - DropdownMenuItem(value: all, child: Text(all)), - DropdownMenuItem(value: personal, child: Text(personal)), - DropdownMenuItem(value: global, child: Text(global)), - ], - style: theme.labelMedium.override( - fontFamily: theme.labelMediumFamily, + items: dropdownItems.entries + .map((entry) => DropdownMenuItem( + value: entry.key, + child: Text(entry.key), + )) + .toList(), + style: theme.bodyMedium.copyWith( color: theme.primaryText, - useGoogleFonts: - GoogleFonts.asMap().containsKey(theme.labelMediumFamily), ), ); }, @@ -144,21 +162,22 @@ class _MessageWellComponentWidgetState ); } - Text _buildHandleMessageWell( - BuildContext context, FlutterFlowTheme theme) { + Text _buildHandleMessageWell(BuildContext context, FlutterFlowTheme theme) { return Text( - FFLocalizations.of(context).getText('8fworxmb'), - style: theme.bodyMedium.override( + FFLocalizations.of(context).getVariableText( + ptText: 'Mural de Mensagens', + enText: 'Message Wall', + ), + style: theme.bodyMedium.copyWith( fontFamily: 'Nunito Sans', letterSpacing: 0.0, - useGoogleFonts: GoogleFonts.asMap().containsKey('Nunito Sans'), ), ); } Widget _buildMessageItem( BuildContext context, dynamic message, int index) { - final theme = Theme.of(context); + final theme = FlutterFlowTheme.of(context); String formatMessageOrigin(String messageOrigin) { final words = messageOrigin.split(' '); final formattedWords = words.map((word) { @@ -168,17 +187,15 @@ class _MessageWellComponentWidgetState }); return formattedWords.join(' '); } - return GestureDetector( - onTap: () => - log('Message tapped ...\nmessage[$index]: $message'), + onTap: () => {}, child: Padding( padding: const EdgeInsets.fromLTRB(20, 5, 20, 5), child: Container( width: MediaQuery.of(context).size.width * 0.9, height: 127.0, - decoration: const BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(10)), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), ), child: Row( mainAxisSize: MainAxisSize.max, @@ -201,9 +218,9 @@ class _MessageWellComponentWidgetState Center( child: Text( '~ ${formatMessageOrigin(message['MSG_ORIGEM_DESC'].toString())}', - style: theme.textTheme.headlineMedium!.copyWith( + style: theme.bodyMedium.copyWith( fontFamily: 'Nunito Sans', - color: FlutterFlowTheme.of(context).primary, + color: theme.primary, fontSize: 14.0, fontWeight: FontWeight.bold, ), @@ -215,9 +232,9 @@ class _MessageWellComponentWidgetState scrollDirection: Axis.vertical, child: Text( formatMessageOrigin(message['MSG_TEXTO'].toString()), - style: theme.textTheme.bodyMedium!.copyWith( + style: theme.bodyMedium.copyWith( fontFamily: 'Nunito Sans', - color: FlutterFlowTheme.of(context).primaryText, + color: theme.bodyMedium.color, fontSize: 14.0, ), softWrap: true, @@ -234,26 +251,25 @@ class _MessageWellComponentWidgetState ), ); } + + } class MessageWellState { final List messages; int pageNumber; final bool allowScrollInSingleChildScrollView; - final ScrollController listViewController; MessageWellState({ required this.messages, this.pageNumber = 1, required this.allowScrollInSingleChildScrollView, - required this.listViewController, }); MessageWellState copyWith({ List? messages, int? pageNumber, bool? allowScrollInSingleChildScrollView, - ScrollController? listViewController, }) { return MessageWellState( messages: messages ?? this.messages, @@ -261,7 +277,6 @@ class MessageWellState { allowScrollInSingleChildScrollView: allowScrollInSingleChildScrollView ?? this.allowScrollInSingleChildScrollView, - listViewController: listViewController ?? this.listViewController, ); } } @@ -274,17 +289,15 @@ class MessageWellNotifier extends StateNotifier { _totalPageNumber = value; } - MessageWellNotifier() : super(MessageWellState( - messages: [], - allowScrollInSingleChildScrollView: true, - listViewController: ScrollController())) { - state.listViewController.addListener(_scrollListener); + messages: [], + allowScrollInSingleChildScrollView: true, + )) { fetchMessages(); } - void fetchMessages() async { + void fetchMessages() async { if (state.pageNumber <= totalPageNumber) { var apiCall = GetMessagesCall(); var response = await apiCall.call( @@ -292,28 +305,20 @@ class MessageWellNotifier extends StateNotifier { userUUID: FFAppState().userUUID.toString(), cliID: FFAppState().cliUUID.toString(), atividade: 'getMensagens', - pageSize: '10', + pageSize: '100', pageNumber: state.pageNumber.toString(), - tipoDestino: 'A', + tipoDestino: dropdown.value.values.first, ); if (response.statusCode == 200) { var messagesData = response.jsonBody['mensagens']; - log('inputs: ${FFAppState().devUUID}, ${FFAppState().userUUID}, ${FFAppState().cliUUID}'); - log('response: ${response.jsonBody}'); - log('response[mensagens]: $messagesData'); - log('response[mensagens][0][MSG_TEXTO]: ${messagesData[0]['MSG_TEXTO']}'); var newMessages = [...state.messages, ...messagesData]; - var rExp = RegExp(r'\d+') - .allMatches(newMessages.toString()) - .map((e) => e.group(0)) - .toList(); - log('rExp: $rExp'); - log('newMessages: $newMessages'); state = state.copyWith(messages: newMessages); - log('total_pages :> ${response.jsonBody['total_pages']}'); + // var rExp = RegExp(r'\d+') + // .allMatches(newMessages.toString()) + // .map((e) => e.group(0)) + // .toList(); // Provider.of(context, listen: false).setCounter(int.parse(response.jsonBody['total_pages'])); - totalPageNumber = int.parse(response.jsonBody['total_pages']); - log('totalPageNumber: $totalPageNumber'); + // totalPageNumber = int.parse(response.jsonBody['total_pages']); } else { log('Error fetching messages: ${response.statusCode}'); } @@ -325,29 +330,9 @@ class MessageWellNotifier extends StateNotifier { List getMessages() { return state.messages; } - - void _scrollListener() { - if (!state.allowScrollInSingleChildScrollView) { - if (state.pageNumber <= totalPageNumber) { - state = state.copyWith(pageNumber: state.pageNumber + 1); - log('state.pageNumber: ${state.pageNumber}'); - fetchMessages(); - } - } - } - - @override - void dispose() { - state.listViewController.removeListener(_scrollListener); - super.dispose(); - } - void incrementPageNumber() { - log('state.pageNumber: ${state.pageNumber}'); - log('total_pages :>: $totalPageNumber'); if (state.pageNumber <= totalPageNumber) { state = state.copyWith(pageNumber: state.pageNumber + 1); - } } } diff --git a/lib/components/templates_components/change_passs_qr_code_pass_key_template_component/change_pass_model.dart b/lib/components/templates_components/change_passs_qr_code_pass_key_template_component/change_pass_model.dart new file mode 100644 index 00000000..c2febab7 --- /dev/null +++ b/lib/components/templates_components/change_passs_qr_code_pass_key_template_component/change_pass_model.dart @@ -0,0 +1,45 @@ +import '/flutter_flow/flutter_flow_util.dart'; +import 'change_pass_widget.dart' + show PassKeyTemplateWidget; +import 'package:flutter/material.dart'; + +class PassKeyTemplateComponentModel + extends FlutterFlowModel { + /// State fields for stateful widgets in this component. + + final formKey = GlobalKey(); + // State field(s) for keyTextField widget. + FocusNode? keyTextFieldFocusNode1; + FocusNode? keyTextFieldFocusNode2; + TextEditingController? keyTextFieldTextController1; + TextEditingController? keyTextFieldTextController2; + late bool keyTextFieldVisibility1; + late bool keyTextFieldVisibility2; + String? Function(BuildContext, String?)? keyTextFieldTextControllerValidator1; + String? Function(BuildContext, String?)? keyTextFieldTextControllerValidator2; + String? _keyTextFieldTextControllerValidator( + BuildContext context, String? val) { + if (val == null || val.isEmpty) { + return FFLocalizations.of(context).getText( + 'f128ajey' /* Field is required */, + ); + } + return null; + } + + @override + void initState(BuildContext context) { + keyTextFieldVisibility1 = false; + keyTextFieldVisibility2 = false; + keyTextFieldTextControllerValidator1 = _keyTextFieldTextControllerValidator; + keyTextFieldTextControllerValidator2 = _keyTextFieldTextControllerValidator; + } + + @override + void dispose() { + keyTextFieldFocusNode1?.dispose(); + keyTextFieldFocusNode2?.dispose(); + keyTextFieldTextController1?.dispose(); + keyTextFieldTextController2?.dispose(); + } +} diff --git a/lib/components/templates_components/change_passs_qr_code_pass_key_template_component/change_pass_widget.dart b/lib/components/templates_components/change_passs_qr_code_pass_key_template_component/change_pass_widget.dart new file mode 100644 index 00000000..16bd3be8 --- /dev/null +++ b/lib/components/templates_components/change_passs_qr_code_pass_key_template_component/change_pass_widget.dart @@ -0,0 +1,458 @@ +import '/flutter_flow/flutter_flow_theme.dart'; +import '/flutter_flow/flutter_flow_util.dart'; +import '/flutter_flow/flutter_flow_widgets.dart'; +import 'package:easy_debounce/easy_debounce.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'change_pass_model.dart'; +export 'change_pass_model.dart'; + +class PassKeyTemplateWidget extends StatefulWidget { + const PassKeyTemplateWidget({ + super.key, + required this.toggleActionStatus, + }); + + final Future Function(String key)? toggleActionStatus; + + @override + State createState() => + _PassKeyTemplateWidgetState(); +} + +class _PassKeyTemplateWidgetState + extends State { + late PassKeyTemplateComponentModel _model; + + @override + void setState(VoidCallback callback) { + super.setState(callback); + _model.onUpdate(); + } + + @override + void initState() { + super.initState(); + _model = createModel(context, () => PassKeyTemplateComponentModel()); + + _model.keyTextFieldTextController1 ??= TextEditingController(); + _model.keyTextFieldFocusNode1 ??= FocusNode(); + _model.keyTextFieldFocusNode1!.addListener(() => setState(() {})); + } + + @override + void dispose() { + _model.maybeDispose(); + + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Align( + alignment: const AlignmentDirectional(0.0, 1.0), + child: Container( + width: double.infinity, + height: 400.0, + constraints: const BoxConstraints( + maxWidth: 570.0, + ), + decoration: BoxDecoration( + color: FlutterFlowTheme.of(context).primaryBackground, + borderRadius: const BorderRadius.only( + bottomLeft: Radius.circular(0.0), + bottomRight: Radius.circular(0.0), + topLeft: Radius.circular(15.0), + topRight: Radius.circular(15.0), + ), + ), + child: Column( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // This row exists for when the "app bar" is hidden on desktop, having a way back for the user can work well. + if (responsiveVisibility( + context: context, + phone: false, + tablet: false, + )) + Padding( + padding: const EdgeInsetsDirectional.fromSTEB(16.0, 0.0, 16.0, 8.0), + child: InkWell( + splashColor: Colors.transparent, + focusColor: Colors.transparent, + hoverColor: Colors.transparent, + highlightColor: Colors.transparent, + onTap: () async { + context.safePop(); + }, + child: Row( + mainAxisSize: MainAxisSize.max, + children: [ + const Padding( + padding: EdgeInsetsDirectional.fromSTEB( + 0.0, 12.0, 0.0, 12.0), + child: Icon( + Icons.arrow_back_rounded, + color: Color(0xFF15161E), + size: 24.0, + ), + ), + Padding( + padding: + const EdgeInsetsDirectional.fromSTEB(12.0, 0.0, 0.0, 0.0), + child: Text( + '', + style: + FlutterFlowTheme.of(context).bodyMedium.override( + fontFamily: 'Plus Jakarta Sans', + color: const Color(0xFF15161E), + fontSize: 14.0, + letterSpacing: 0.0, + fontWeight: FontWeight.w500, + useGoogleFonts: GoogleFonts.asMap() + .containsKey('Plus Jakarta Sans'), + ), + ), + ), + ], + ), + ), + ), + Padding( + padding: const EdgeInsetsDirectional.fromSTEB(16.0, 0.0, 0.0, 0.0), + child: Text( + FFLocalizations.of(context).getVariableText( + enText: FFAppState().accessPass != '' ? 'CHANGE PASSWORD' : 'INSERT PASSWORD', + ptText: FFAppState().accessPass != '' ? 'ALTERAR SENHA' : 'ADICIONAR SENHA', + ), + style: FlutterFlowTheme.of(context).headlineMedium.override( + fontFamily: 'Outfit', + color: FlutterFlowTheme.of(context).primaryText, + fontSize: 24.0, + letterSpacing: 0.0, + fontWeight: FontWeight.w500, + useGoogleFonts: GoogleFonts.asMap().containsKey('Outfit'), + ), + ), + ), + Padding( + padding: const EdgeInsetsDirectional.fromSTEB(16.0, 4.0, 16.0, 4.0), + child: Text( + FFLocalizations.of(context).getVariableText( + enText: 'Enter your password to continue', + ptText: 'Digite sua senha para continuar' + ), + style: FlutterFlowTheme.of(context).labelMedium.override( + fontFamily: 'Plus Jakarta Sans', + color: FlutterFlowTheme.of(context).primaryText, + fontSize: 14.0, + letterSpacing: 0.0, + fontWeight: FontWeight.w500, + useGoogleFonts: + GoogleFonts.asMap().containsKey('Plus Jakarta Sans'), + ), + ), + ), + Form( + key: _model.formKey, + autovalidateMode: AutovalidateMode.always, + child: Column( + children: [ + if (FFAppState().accessPass.isNotEmpty) + Padding( + padding: const EdgeInsetsDirectional.fromSTEB(16.0, 12.0, 16.0, 0.0), + child: SizedBox( + width: double.infinity, + child: TextFormField( + controller: _model.keyTextFieldTextController1, + + focusNode: _model.keyTextFieldFocusNode1, + onChanged: (_) => EasyDebounce.debounce( + '_model.keyTextFieldTextController', + const Duration(milliseconds: 2000), + () => setState(() {}), + ), + autofillHints: const [AutofillHints.password], + textCapitalization: TextCapitalization.none, + textInputAction: TextInputAction.done, + obscureText: !_model.keyTextFieldVisibility1, + decoration: InputDecoration( + isDense: true, + labelText: FFLocalizations.of(context).getVariableText( + ptText: 'Senha Antiga', + enText: 'Old Password', + ), + labelStyle: + FlutterFlowTheme.of(context).labelMedium.override( + fontFamily: 'Plus Jakarta Sans', + color: FlutterFlowTheme.of(context).primary, + fontSize: 14.0, + letterSpacing: 0.0, + fontWeight: FontWeight.w500, + useGoogleFonts: GoogleFonts.asMap() + .containsKey('Plus Jakarta Sans'), + ), + hintText: FFLocalizations.of(context).getVariableText( + ptText: 'Digite a sua senha antiga.....', + enText: 'Enter your old password.....', + ), + hintStyle: + FlutterFlowTheme.of(context).labelMedium.override( + fontFamily: 'Plus Jakarta Sans', + color: FlutterFlowTheme.of(context).primaryText, + fontSize: 14.0, + letterSpacing: 0.0, + fontWeight: FontWeight.w500, + useGoogleFonts: GoogleFonts.asMap() + .containsKey('Plus Jakarta Sans'), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: FlutterFlowTheme.of(context).accent1, + width: 2.0, + ), + borderRadius: BorderRadius.circular(12.0), + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: FlutterFlowTheme.of(context).accent3, + width: 2.0, + ), + borderRadius: BorderRadius.circular(12.0), + ), + errorBorder: OutlineInputBorder( + borderSide: BorderSide( + color: FlutterFlowTheme.of(context).error, + width: 2.0, + ), + borderRadius: BorderRadius.circular(12.0), + ), + focusedErrorBorder: OutlineInputBorder( + borderSide: BorderSide( + color: FlutterFlowTheme.of(context).error, + width: 2.0, + ), + borderRadius: BorderRadius.circular(12.0), + ), + filled: true, + fillColor: FlutterFlowTheme.of(context).primaryBackground, + contentPadding: const EdgeInsetsDirectional.fromSTEB( + 24.0, 24.0, 20.0, 24.0), + suffixIcon: InkWell( + onTap: () => setState( + () => _model.keyTextFieldVisibility1 = + !_model.keyTextFieldVisibility1, + ), + focusNode: FocusNode(skipTraversal: true), + child: Icon( + _model.keyTextFieldVisibility1 + ? Icons.visibility_outlined + : Icons.visibility_off_outlined, + color: FlutterFlowTheme.of(context).accent1, + size: 22.0, + ), + ), + ), + style: FlutterFlowTheme.of(context).bodyMedium.override( + fontFamily: 'Plus Jakarta Sans', + color: FlutterFlowTheme.of(context).primaryText, + fontSize: 14.0, + letterSpacing: 0.0, + fontWeight: FontWeight.w500, + useGoogleFonts: GoogleFonts.asMap() + .containsKey('Plus Jakarta Sans'), + ), + maxLength: 4, + maxLengthEnforcement: MaxLengthEnforcement.none, + buildCounter: (context, + {required currentLength, + required isFocused, + maxLength}) => + null, + keyboardType: TextInputType.number, + cursorColor: FlutterFlowTheme.of(context).primary, + validator: _model.keyTextFieldTextControllerValidator1 + .asValidator(context), + inputFormatters: [ + FilteringTextInputFormatter.allow(RegExp('[0-9]')) + ], + ), + ), + ), + Padding( + padding: const EdgeInsetsDirectional.fromSTEB(16.0, 12.0, 16.0, 0.0), + child: SizedBox( + width: double.infinity, + child: TextFormField( + controller: _model.keyTextFieldTextController2, + + focusNode: _model.keyTextFieldFocusNode2, + onChanged: (_) => EasyDebounce.debounce( + '_model.keyTextFieldTextController', + const Duration(milliseconds: 2000), + () => setState(() {}), + ), + autofillHints: const [AutofillHints.password], + textCapitalization: TextCapitalization.none, + textInputAction: TextInputAction.done, + obscureText: !_model.keyTextFieldVisibility2, + decoration: InputDecoration( + isDense: true, + labelText: FFLocalizations.of(context).getVariableText( + ptText: FFAppState().accessPass != '' ? 'Nova Senha' : 'Senha', + enText: FFAppState().accessPass != '' ? 'New Password' : 'Password', + ), + labelStyle: + FlutterFlowTheme.of(context).labelMedium.override( + fontFamily: 'Plus Jakarta Sans', + color: FlutterFlowTheme.of(context).primary, + fontSize: 14.0, + letterSpacing: 0.0, + fontWeight: FontWeight.w500, + useGoogleFonts: GoogleFonts.asMap() + .containsKey('Plus Jakarta Sans'), + ), + hintText: FFLocalizations.of(context).getVariableText( + enText: FFAppState().accessPass != null ? 'Enter your new password.....' : 'Enter your password.....', + ptText: FFAppState().accessPass != null ? 'Digite a sua nova senha.....' : 'Digite a sua senha.....', + ), + hintStyle: + FlutterFlowTheme.of(context).labelMedium.override( + fontFamily: 'Plus Jakarta Sans', + color: FlutterFlowTheme.of(context).primaryText, + fontSize: 14.0, + letterSpacing: 0.0, + fontWeight: FontWeight.w500, + useGoogleFonts: GoogleFonts.asMap() + .containsKey('Plus Jakarta Sans'), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: FlutterFlowTheme.of(context).accent1, + width: 2.0, + ), + borderRadius: BorderRadius.circular(12.0), + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: FlutterFlowTheme.of(context).accent3, + width: 2.0, + ), + borderRadius: BorderRadius.circular(12.0), + ), + errorBorder: OutlineInputBorder( + borderSide: BorderSide( + color: FlutterFlowTheme.of(context).error, + width: 2.0, + ), + borderRadius: BorderRadius.circular(12.0), + ), + focusedErrorBorder: OutlineInputBorder( + borderSide: BorderSide( + color: FlutterFlowTheme.of(context).error, + width: 2.0, + ), + borderRadius: BorderRadius.circular(12.0), + ), + filled: true, + fillColor: FlutterFlowTheme.of(context).primaryBackground, + contentPadding: const EdgeInsetsDirectional.fromSTEB( + 24.0, 24.0, 20.0, 24.0), + suffixIcon: InkWell( + onTap: () => setState( + () => _model.keyTextFieldVisibility1 = + !_model.keyTextFieldVisibility1, + ), + focusNode: FocusNode(skipTraversal: true), + child: Icon( + _model.keyTextFieldVisibility1 + ? Icons.visibility_outlined + : Icons.visibility_off_outlined, + color: FlutterFlowTheme.of(context).accent1, + size: 22.0, + ), + ), + ), + style: FlutterFlowTheme.of(context).bodyMedium.override( + fontFamily: 'Plus Jakarta Sans', + color: FlutterFlowTheme.of(context).primaryText, + fontSize: 14.0, + letterSpacing: 0.0, + fontWeight: FontWeight.w500, + useGoogleFonts: GoogleFonts.asMap() + .containsKey('Plus Jakarta Sans'), + ), + maxLength: 4, + maxLengthEnforcement: MaxLengthEnforcement.none, + buildCounter: (context, + {required currentLength, + required isFocused, + maxLength}) => + null, + keyboardType: TextInputType.number, + cursorColor: FlutterFlowTheme.of(context).primary, + validator: _model.keyTextFieldTextControllerValidator2 + .asValidator(context), + inputFormatters: [ + FilteringTextInputFormatter.allow(RegExp('[0-9]')) + ], + ), + ), + ), + ], + ), + ), + Align( + alignment: const AlignmentDirectional(0.0, 0.0), + child: Padding( + padding: const EdgeInsetsDirectional.fromSTEB(0.0, 24.0, 0.0, 0.0), + child: FFButtonWidget( + onPressed: () async { + if (_model.formKey.currentState == null || + !_model.formKey.currentState!.validate()) { + return; + } + await widget.toggleActionStatus?.call( + _model.keyTextFieldTextController1.text.isEmpty ? _model.keyTextFieldTextController2.text : _model.keyTextFieldTextController1.text, + ); + Navigator.pop(context); + }, + text: FFLocalizations.of(context).getVariableText( + ptText: FFAppState().accessPass != '' ? 'Alterar' : 'Adicionar', + enText: FFAppState().accessPass != '' ? 'Change' : 'Add', + ), + options: FFButtonOptions( + width: 270.0, + height: 50.0, + padding: const EdgeInsetsDirectional.fromSTEB(0.0, 0.0, 0.0, 0.0), + iconPadding: + const EdgeInsetsDirectional.fromSTEB(0.0, 0.0, 0.0, 0.0), + color: const Color(0xFF1AAB5F), + textStyle: FlutterFlowTheme.of(context).titleSmall.override( + fontFamily: 'Plus Jakarta Sans', + color: Colors.white, + fontSize: 16.0, + letterSpacing: 0.0, + fontWeight: FontWeight.w500, + useGoogleFonts: GoogleFonts.asMap() + .containsKey('Plus Jakarta Sans'), + ), + elevation: 3.0, + borderSide: const BorderSide( + color: Colors.transparent, + width: 1.0, + ), + ), + showLoadingIndicator: false, + ), + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/components/view_visit_detail/view_visit_detail_widget.dart b/lib/components/view_visit_detail/view_visit_detail_widget.dart index 0394cbcf..e5c4195f 100644 --- a/lib/components/view_visit_detail/view_visit_detail_widget.dart +++ b/lib/components/view_visit_detail/view_visit_detail_widget.dart @@ -9,6 +9,7 @@ import '/flutter_flow/flutter_flow_theme.dart'; import '/flutter_flow/flutter_flow_util.dart'; import '/actions/actions.dart' as action_blocks; import 'package:cached_network_image/cached_network_image.dart'; +import 'package:share_plus/share_plus.dart'; import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; import 'package:google_fonts/google_fonts.dart'; @@ -862,6 +863,11 @@ class _ViewVisitDetailWidgetState extends State { ), onPressed: () { log('IconButton pressed ...'); + // Implement share functionality here + Share.share( + 'Visita agendada para ${widget.visitStartDate} com término previsto para ${widget.visitEndDate}. Motivo: ${widget.visitReasonStr}. Nível de acesso: ${widget.visitLevelStr}. Observações: ${widget.visitObsStr}.', + ); + }, ), ], diff --git a/lib/flutter_flow/nav/nav.dart b/lib/flutter_flow/nav/nav.dart index 20644421..6eed8f03 100644 --- a/lib/flutter_flow/nav/nav.dart +++ b/lib/flutter_flow/nav/nav.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:f_r_e_hub/pages/fast_pass_page/fast_pass_page_widget.dart'; import 'package:f_r_e_hub/pages/message_history_page/message_history_page_widget.dart'; +import 'package:f_r_e_hub/pages/preferences_settings_page/preferences_settings_widget.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; @@ -78,7 +79,10 @@ GoRouter createRouter(AppStateNotifier appStateNotifier) => GoRouter( path: '/visitHistoryPage', builder: (context, params) => const VisitHistoryPageWidget(), ), - FFRoute(name: 'messageHistoryPage', path: '/messageHistoryPage', builder: (context, params) => const MessageHistoryPageWidget()), + FFRoute( + name: 'messageHistoryPage', + path: '/messageHistoryPage', + builder: (context, params) => const MessageHistoryPageWidget()), FFRoute( name: 'registerVisitorPage', path: '/registerVisitorPage', @@ -138,6 +142,9 @@ GoRouter createRouter(AppStateNotifier appStateNotifier) => GoRouter( path: '/fastPassPage', builder: (context, params) => /*const*/ FastPassPageWidget(), ), + FFRoute(name: 'preferencesSettings', path: '/preferencesSettings', builder: (context, params) => const PreferencesPageWidget( + key: Key('preferencesSettings'), + )), FFRoute( name: 'peopleOnThePropertyPage', path: '/peopleOnThePropertyPage', diff --git a/lib/flutter_flow/permissions_util.dart b/lib/flutter_flow/permissions_util.dart new file mode 100644 index 00000000..c7b8c2ff --- /dev/null +++ b/lib/flutter_flow/permissions_util.dart @@ -0,0 +1,18 @@ +import 'package:flutter/foundation.dart'; +import 'package:permission_handler/permission_handler.dart'; + +const kPermissionStateToBool = { + PermissionStatus.granted: true, + PermissionStatus.limited: true, + PermissionStatus.denied: false, + PermissionStatus.restricted: false, + PermissionStatus.permanentlyDenied: false, +}; + +Future getPermissionStatus(Permission setting) async { + final status = await setting.status; + return kPermissionStateToBool[status]!; +} + +Future requestPermission(Permission setting) async => + await setting.request(); diff --git a/lib/main.dart b/lib/main.dart index e9e8d587..9bc5efc1 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,10 +1,3 @@ -// import 'package:f_r_e_hub/backend/api_requests/api_calls.dart'; -// import 'package:f_r_e_hub/backend/push_notification/pushNotificationService.dart'; -// import 'package:f_r_e_hub/components/templates_components/visit_request_template_component/visit_request_template_component_widget.dart'; -// import 'package:firebase_messaging/firebase_messaging.dart'; -// import 'package:flutter_local_notifications/flutter_local_notifications.dart'; -// import 'package:firebase_analytics/firebase_analytics.dart'; - import 'package:firebase_core/firebase_core.dart'; import 'package:provider/provider.dart'; diff --git a/lib/pages/liberation_history/liberation_history_widget.dart b/lib/pages/liberation_history/liberation_history_widget.dart index 2799de6b..29443a9d 100644 --- a/lib/pages/liberation_history/liberation_history_widget.dart +++ b/lib/pages/liberation_history/liberation_history_widget.dart @@ -75,6 +75,7 @@ PreferredSizeWidget appBarLiberationHistoryPage(BuildContext context) { return AppBar( backgroundColor: FlutterFlowTheme.of(context).primaryBackground, automaticallyImplyLeading: false, + forceMaterialTransparency: true, leading: FlutterFlowIconButton( borderColor: Colors.transparent, borderRadius: 30.0, @@ -103,6 +104,7 @@ PreferredSizeWidget appBarLiberationHistoryPage(BuildContext context) { ), actions: const [], centerTitle: true, + elevation: 0.0, ); } diff --git a/lib/pages/people_on_the_property_page/people_on_the_property_page_widget.dart b/lib/pages/people_on_the_property_page/people_on_the_property_page_widget.dart index 6eff0d55..aed5b8f0 100644 --- a/lib/pages/people_on_the_property_page/people_on_the_property_page_widget.dart +++ b/lib/pages/people_on_the_property_page/people_on_the_property_page_widget.dart @@ -51,6 +51,7 @@ class _PeopleOnThePropertyPageWidgetState appBar: AppBar( backgroundColor: FlutterFlowTheme.of(context).primaryBackground, automaticallyImplyLeading: false, + forceMaterialTransparency: true, leading: FlutterFlowIconButton( borderColor: Colors.transparent, borderRadius: 30.0, @@ -106,7 +107,6 @@ class _PeopleOnThePropertyPageWidgetState ); } final columnGetPessoasLocalResponse = snapshot.data!; - return Builder( builder: (context) { final getPoepleProperty = PhpGroup.getPessoasLocalCall diff --git a/lib/pages/preferences_settings_page/preferences_settings_model.dart b/lib/pages/preferences_settings_page/preferences_settings_model.dart new file mode 100644 index 00000000..164d8677 --- /dev/null +++ b/lib/pages/preferences_settings_page/preferences_settings_model.dart @@ -0,0 +1,115 @@ + +import 'package:f_r_e_hub/backend/api_requests/api_calls.dart'; +import 'package:f_r_e_hub/components/templates_components/change_passs_qr_code_pass_key_template_component/change_pass_widget.dart'; +import 'package:f_r_e_hub/flutter_flow/flutter_flow_theme.dart'; +import 'package:f_r_e_hub/flutter_flow/flutter_flow_util.dart'; +import 'package:flutter/material.dart'; +import 'package:local_auth/local_auth.dart'; + +class PreferencesPageModel with ChangeNotifier { + final unfocusNode = FocusNode(); + + final LocalAuthentication auth = LocalAuthentication(); + + + Future toggleFingerprint() async { + + FFAppState().checkBiometrics().then((value) => FFAppState().authenticateBiometric().then( (value) => FFAppState().fingerprint = !FFAppState().fingerprint).whenComplete(() => notifyListeners())); + + + } + + void enablePerson(BuildContext context) { + + notifyListeners(); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(FFAppState().userDevUUID, style: TextStyle(color: FlutterFlowTheme.of(context).info) ), + backgroundColor: FlutterFlowTheme.of(context).primary, + duration: const Duration(seconds: 1), + behavior: SnackBarBehavior.floating, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(30), + ), + ), + ); + } + + void toggleNotify() { + FFAppState().notify = !FFAppState().notify; + PhpGroup.changeNotifica.call( + userUUID: FFAppState().userUUID, + devUUID: FFAppState().devUUID, + cliID: FFAppState().cliUUID, + atividade: 'updVisitado', + notifica: FFAppState().notify ? 'S' : 'N', + ); + notifyListeners(); + } + + void localLogout(){ + PhpGroup.resopndeVinculo.call( + userUUID: FFAppState().userUUID, + devUUID: FFAppState().devUUID, + cliID: FFAppState().cliUUID, + tarefa: 'I', + ); + notifyListeners(); + } + + void deleteAccount(BuildContext context) { + FFAppState().deleteAll(); + FFAppState().isLogged = false; + context.goNamed( + 'welcomePage', + extra: { + kTransitionInfoKey: const TransitionInfo( + hasTransition: true, + transitionType: PageTransitionType.scale, + alignment: Alignment.bottomCenter, + ), + }, + ); + } + + + Future togglePass(BuildContext context) async { + FFAppState().pass = true; + notifyListeners(); + await showModalBottomSheet( + isScrollControlled: true, + backgroundColor: Colors.transparent, + useSafeArea: true, + context: context, + builder: (context) { + return Padding( + padding: + MediaQuery.viewInsetsOf(context), + child: + PassKeyTemplateWidget( + toggleActionStatus: (key) async { + FFAppState().accessPass = key; + notifyListeners(); + debugPrint('key: $key'); + // PhpGroup.changePass.call( + // userUUID: FFAppState().userUUID, + // devUUID: FFAppState().devUUID, + // cliID: FFAppState().cliUUID, + // atividade: 'updVisitado', + // newSenha: FFAppState().accessPass, + // ); + }, + ), + ); + }, + ); + FFAppState().pass = false; + notifyListeners(); + } + + @override + void dispose() { + unfocusNode.dispose(); + super.dispose(); + } +} \ No newline at end of file diff --git a/lib/pages/preferences_settings_page/preferences_settings_widget.dart b/lib/pages/preferences_settings_page/preferences_settings_widget.dart new file mode 100644 index 00000000..c8955d1a --- /dev/null +++ b/lib/pages/preferences_settings_page/preferences_settings_widget.dart @@ -0,0 +1,140 @@ +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:provider/provider.dart'; +import '/flutter_flow/flutter_flow_icon_button.dart'; +import '/flutter_flow/flutter_flow_theme.dart'; +import '/flutter_flow/flutter_flow_util.dart'; +import 'preferences_settings_model.dart'; + +class PreferencesPageWidget extends StatelessWidget { + const PreferencesPageWidget({super.key}); + + @override + Widget build(BuildContext context) { + return ChangeNotifierProvider( + create: (_) => PreferencesPageModel(), + child: Consumer( + builder: (context, model, child) => GestureDetector( + onTap: () => model.unfocusNode.canRequestFocus + ? FocusScope.of(context).requestFocus(model.unfocusNode) + : FocusScope.of(context).unfocus(), + child: Scaffold( + backgroundColor: FlutterFlowTheme.of(context).primaryBackground, + appBar: AppBar( + backgroundColor: FlutterFlowTheme.of(context).primaryBackground, + automaticallyImplyLeading: false, + forceMaterialTransparency: true, + 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( + enText: 'Preferences', + ptText: 'Preferências', + ), + style: FlutterFlowTheme.of(context).headlineMedium.override( + fontFamily: 'Nunito', + color: FlutterFlowTheme.of(context).primaryText, + fontSize: 17.0, + letterSpacing: 0.0, + useGoogleFonts: GoogleFonts.asMap().containsKey('Nunito'), + ), + ), + centerTitle: true, + elevation: 0.0, + ), + body: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.max, + children: [ + Container(), + Expanded( + flex: 2, + child: GridView.builder( + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 3, + crossAxisSpacing: 12.0, + mainAxisSpacing: 12.0, + childAspectRatio: 1.0, + mainAxisExtent: 100.0, + ), + itemCount: 6, // Assuming 4 items for simplicity + padding: const EdgeInsets.symmetric(horizontal: 20.0), + physics: const AlwaysScrollableScrollPhysics(), + itemBuilder: (BuildContext context, int index) { + return _buildIconButton(context, index, model); + }, + ), + ), + ], + ), + ), + ), + ), + ); + } + + Widget _buildIconButton(BuildContext context, int index, PreferencesPageModel model) { + IconData icon; + Function() onPressed =() => {}; + bool isEnabled; + + switch (index) { + case 0: + icon = Icons.fingerprint; + onPressed = model.toggleFingerprint; // Desabilita se fingerprint for false + isEnabled = FFAppState().fingerprint; + break; + case 1: + icon = Icons.person; + onPressed = () => model.enablePerson(context); + isEnabled = FFAppState().person; + break; + case 2: + icon = Icons.notifications; + onPressed = model.toggleNotify; + isEnabled = FFAppState().notify; + break; + case 3: + icon = Icons.lock_clock_sharp; + // onLongPress = model.togglePass(context, model); + isEnabled = FFAppState().pass; + break; + case 4: + icon = Icons.landscape; + onPressed = model.localLogout; + isEnabled = false; + break; + case 5: + icon = Icons.delete; + onPressed = () => model.deleteAccount(context); + isEnabled = false; + break; + default: + throw Exception('Invalid index: $index'); + } + + return FlutterFlowIconButton( + icon: Icon(icon, color: isEnabled ? FlutterFlowTheme.of(context).primaryBackground : FlutterFlowTheme.of(context).primary, size: 40.0), + onPressed: index != 3 ? onPressed : () {model.togglePass(context);}, + borderRadius: 20.0, + borderWidth: 1.0, + buttonSize: 40.0, + fillColor: isEnabled ? FlutterFlowTheme.of(context).primary : FlutterFlowTheme.of(context).alternate, + disabledColor: FlutterFlowTheme.of(context).alternate, + disabledIconColor: FlutterFlowTheme.of(context).primary, + ); + } +} \ No newline at end of file diff --git a/lib/pages/register_visitor_page/register_visitor_page_widget.dart b/lib/pages/register_visitor_page/register_visitor_page_widget.dart index 6f9e7722..fb885d1b 100644 --- a/lib/pages/register_visitor_page/register_visitor_page_widget.dart +++ b/lib/pages/register_visitor_page/register_visitor_page_widget.dart @@ -66,6 +66,7 @@ class _RegisterVisitorPageWidgetState extends State { appBar: AppBar( backgroundColor: FlutterFlowTheme.of(context).primaryBackground, automaticallyImplyLeading: false, + forceMaterialTransparency: true, leading: FlutterFlowIconButton( borderColor: Colors.transparent, borderRadius: 30.0, diff --git a/lib/pages/schedule_complete_visit_page/schedule_complete_visit_page_widget.dart b/lib/pages/schedule_complete_visit_page/schedule_complete_visit_page_widget.dart index d1a87520..a01ffeb6 100644 --- a/lib/pages/schedule_complete_visit_page/schedule_complete_visit_page_widget.dart +++ b/lib/pages/schedule_complete_visit_page/schedule_complete_visit_page_widget.dart @@ -165,6 +165,8 @@ PreferredSizeWidget appBarScheduleCompleteVisit(BuildContext context) { return AppBar( backgroundColor: FlutterFlowTheme.of(context).primaryBackground, automaticallyImplyLeading: false, + forceMaterialTransparency: true, + elevation: 0.0, leading: FlutterFlowIconButton( borderColor: Colors.transparent, borderRadius: 30.0, diff --git a/lib/pages/schedule_provisional_visit_page/schedule_provisional_visit_page_widget.dart b/lib/pages/schedule_provisional_visit_page/schedule_provisional_visit_page_widget.dart index b8528fa3..1b5639a8 100644 --- a/lib/pages/schedule_provisional_visit_page/schedule_provisional_visit_page_widget.dart +++ b/lib/pages/schedule_provisional_visit_page/schedule_provisional_visit_page_widget.dart @@ -61,6 +61,7 @@ class _ScheduleProvisionalVisitPageWidgetState backgroundColor: FlutterFlowTheme.of(context).primaryBackground, appBar: AppBar( automaticallyImplyLeading: false, + forceMaterialTransparency: true, leading: FlutterFlowIconButton( borderColor: Colors.transparent, borderRadius: 30.0, diff --git a/pubspec.lock b/pubspec.lock index 799ff761..a64d3263 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -821,6 +821,46 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.0" + local_auth: + dependency: "direct main" + description: + name: local_auth + sha256: "280421b416b32de31405b0a25c3bd42dfcef2538dfbb20c03019e02a5ed55ed0" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + local_auth_android: + dependency: transitive + description: + name: local_auth_android + sha256: "33fcebe9c3cf1bb0033bc85caed354c1e75ff7f7670918a571bd3152a2b65bf4" + url: "https://pub.dev" + source: hosted + version: "1.0.42" + local_auth_darwin: + dependency: transitive + description: + name: local_auth_darwin + sha256: e424ebf90d5233452be146d4a7da4bcd7a70278b67791592f3fde1bda8eef9e2 + url: "https://pub.dev" + source: hosted + version: "1.3.1" + local_auth_platform_interface: + dependency: transitive + description: + name: local_auth_platform_interface + sha256: "1b842ff177a7068442eae093b64abe3592f816afd2a533c0ebcdbe40f9d2075a" + url: "https://pub.dev" + source: hosted + version: "1.0.10" + local_auth_windows: + dependency: transitive + description: + name: local_auth_windows + sha256: "505ba3367ca781efb1c50d3132e44a2446bccc4163427bc203b9b4d8994d97ea" + url: "https://pub.dev" + source: hosted + version: "1.0.10" logging: dependency: transitive description: @@ -973,6 +1013,62 @@ packages: url: "https://pub.dev" source: hosted version: "4.2.2" + permission_handler: + dependency: "direct main" + description: + name: permission_handler + sha256: "18bf33f7fefbd812f37e72091a15575e72d5318854877e0e4035a24ac1113ecb" + url: "https://pub.dev" + source: hosted + version: "11.3.1" + permission_handler_android: + dependency: transitive + description: + name: permission_handler_android + sha256: b29a799ca03be9f999aa6c39f7de5209482d638e6f857f6b93b0875c618b7e54 + url: "https://pub.dev" + source: hosted + version: "12.0.7" + permission_handler_apple: + dependency: transitive + description: + name: permission_handler_apple + sha256: e6f6d73b12438ef13e648c4ae56bd106ec60d17e90a59c4545db6781229082a0 + url: "https://pub.dev" + source: hosted + version: "9.4.5" + permission_handler_html: + dependency: transitive + description: + name: permission_handler_html + sha256: "54bf176b90f6eddd4ece307e2c06cf977fb3973719c35a93b85cc7093eb6070d" + url: "https://pub.dev" + source: hosted + version: "0.1.1" + permission_handler_platform_interface: + dependency: transitive + description: + name: permission_handler_platform_interface + sha256: "48d4fcf201a1dad93ee869ab0d4101d084f49136ec82a8a06ed9cfeacab9fd20" + url: "https://pub.dev" + source: hosted + version: "4.2.1" + permission_handler_windows: + dependency: transitive + description: + name: permission_handler_windows + sha256: "1a790728016f79a41216d88672dbc5df30e686e811ad4e698bfc51f76ad91f1e" + url: "https://pub.dev" + source: hosted + version: "0.2.1" + persistent_bottom_nav_bar: + dependency: "direct main" + description: + name: persistent_bottom_nav_bar + sha256: "6aa9b97ced1abd92c90cedd1997d34ea0b35c3ded762ac6063baccc299b0c4c5" + url: "https://pub.dev" + source: hosted + version: "6.2.1" petitparser: dependency: transitive description: @@ -1053,6 +1149,22 @@ packages: url: "https://pub.dev" source: hosted version: "0.27.7" + share_plus: + dependency: "direct main" + description: + name: share_plus + sha256: ef3489a969683c4f3d0239010cc8b7a2a46543a8d139e111c06c558875083544 + url: "https://pub.dev" + source: hosted + version: "9.0.0" + share_plus_platform_interface: + dependency: transitive + description: + name: share_plus_platform_interface + sha256: "0f9e4418835d1b2c3ae78fdb918251959106cefdbc4dd43526e182f80e82f6d4" + url: "https://pub.dev" + source: hosted + version: "4.0.0" shared_preferences: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index acc1ff68..7c09b904 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -47,6 +47,7 @@ dependencies: flutter_animate: 4.5.0 flutter_cache_manager: 3.3.2 flutter_plugin_android_lifecycle: 2.0.20 + share_plus: ^9.0.0 flutter_secure_storage: 9.2.2 flutter_secure_storage_linux: 1.2.1 flutter_secure_storage_macos: 3.1.2 @@ -64,8 +65,10 @@ dependencies: image_picker: 1.1.2 image_picker_android: 0.8.12+3 image_picker_for_web: 3.0.4 + persistent_bottom_nav_bar: ^6.2.1 image_picker_ios: 0.8.12 image_picker_platform_interface: 2.10.0 + local_auth: ^2.2.0 intl: ^0.19.0 json_path: 0.7.2 mime_type: 1.0.0 @@ -103,6 +106,7 @@ dependencies: flutter_bloc: ^8.1.6 flutter_riverpod: ^2.5.1 qr_flutter: ^4.1.0 + permission_handler: ^11.3.1 dependency_overrides: http: 1.2.1