import 'package:flutter/material.dart'; import 'package:hub/backend/api_requests/api_manager.dart'; import 'package:hub/components/molecular_components/message_opt_modal/opt_modal_widget.dart'; import 'package:hub/flutter_flow/flutter_flow_model.dart'; import 'package:hub/flutter_flow/request_manager.dart'; import 'package:hub/shared/helpers/storage/base_storage.dart'; import 'package:hub/shared/helpers/storage/storage_helper.dart'; import 'package:flutter_spinkit/flutter_spinkit.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:hub/backend/api_requests/api_calls.dart'; import 'package:hub/components/templates_components/card_item_template_component/card_item_template_component_widget.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/shared/utils/dialog_util.dart'; import 'package:hub/shared/utils/limited_text_size.dart'; import 'package:hub/shared/utils/log_util.dart'; import 'package:rxdart/rxdart.dart'; class ProvisionalScheduleHistoryModel extends FlutterFlowModel { late final String devUUID; late final String userUUID; late final String cliUUID; final unfocusNode = FocusNode(); final _ProvisionalScheduleHistoryManager = FutureRequestManager(); Future ProvisionalScheduleHistory({ String? uniqueQueryKey, bool? overrideCache, required Future Function() requestFn, }) => _ProvisionalScheduleHistoryManager.performRequest( uniqueQueryKey: uniqueQueryKey, overrideCache: overrideCache, requestFn: requestFn, ); void clearProvisionalScheduleHistoryCache() => _ProvisionalScheduleHistoryManager.clear(); void clearProvisionalScheduleHistoryCacheKey(String? uniqueKey) => _ProvisionalScheduleHistoryManager.clearRequest(uniqueKey); @override void initState(BuildContext context) { initDatabase(); } Future initDatabase() async { devUUID = (await StorageHelper().get(KeychainStorageKey.devUUID.value)) ?? ''; userUUID = (await StorageHelper().get(KeychainStorageKey.userUUID.value)) ?? ''; cliUUID = (await StorageHelper().get(KeychainStorageKey.clientUUID.value)) ?? ''; } @override void dispose() { unfocusNode.dispose(); clearProvisionalScheduleHistoryCache(); } Future toggleOptionsAction(BuildContext context) async { await showModalBottomSheet( isScrollControlled: true, backgroundColor: Colors.transparent, useSafeArea: true, context: context, builder: (context) { return GestureDetector( onTap: () => unfocusNode.canRequestFocus ? FocusScope.of(context).requestFocus(unfocusNode) : FocusScope.of(context).unfocus(), child: Padding( padding: MediaQuery.viewInsetsOf(context), child: const OptModalWidget(), ), ); }, ); } } // ignore: must_be_immutable class ProvisionalScheduleHistoryScreen extends StatefulWidget { late Map opt = { 'personType': '.*', 'accessType': '.*', 'search': '.*', }; ProvisionalScheduleHistoryScreen({super.key, required this.opt}); @override State createState() => _ProvisionalScheduleHistoryState(opt); } class _ProvisionalScheduleHistoryState extends State { late ProvisionalScheduleHistoryModel _model; final BehaviorSubject> selectedTypeSubject; bool _isSubjectClosed = false; final scaffoldKey = GlobalKey(); late ScrollController _scrollController; int _pageNumber = 1; final int _pageSize = 10; bool _hasData = false; bool _loading = false; String _personType = '.*'; late Future _accessFuture; List _accessWrap = []; _ProvisionalScheduleHistoryState(Map opt) : selectedTypeSubject = BehaviorSubject.seeded(opt) { selectedTypeSubject.listen((value) {}); } @override void initState() { super.initState(); _model = createModel(context, () => ProvisionalScheduleHistoryModel()); _accessFuture = fetchProvisionalScheduleHistoryService(); _scrollController = ScrollController() ..addListener(() { if (_scrollController.position.atEdge && _scrollController.position.pixels != 0) { _loadMoreAccess(); } }); } @override void dispose() { selectedTypeSubject.close(); _isSubjectClosed = true; super.dispose(); } @override Widget build(BuildContext context) { final theme = FlutterFlowTheme.of(context); return Scaffold( key: scaffoldKey, backgroundColor: FlutterFlowTheme.of(context).primaryBackground, appBar: _appBar(context, theme), body: _body(context)); } PreferredSizeWidget _appBar(BuildContext context, FlutterFlowTheme theme) { return AppBar( backgroundColor: theme.primaryBackground, automaticallyImplyLeading: false, leading: _backButton(context, theme), title: _title(context, theme), centerTitle: true, elevation: 0.0, actions: [_filterButton(context)], ); } Widget _backButton(BuildContext context, FlutterFlowTheme theme) { return FlutterFlowIconButton( borderColor: Colors.transparent, borderRadius: 30.0, borderWidth: 1.0, buttonSize: 60.0, icon: Icon( Icons.keyboard_arrow_left, color: theme.primaryText, size: 30.0, ), onPressed: () => Navigator.of(context).pop(), ); } Widget _title(BuildContext context, FlutterFlowTheme theme) { return Text( FFLocalizations.of(context).getText('ch8qymga'), style: theme.headlineMedium.override( fontFamily: theme.headlineMediumFamily, color: theme.primaryText, fontSize: 16.0, letterSpacing: 0.0, useGoogleFonts: GoogleFonts.asMap().containsKey(theme.headlineMediumFamily), ), ); } Widget _filterButton(BuildContext context) { return Row( mainAxisAlignment: MainAxisAlignment.end, children: [ Padding( padding: const EdgeInsets.fromLTRB(0, 0, 10, 0), child: IconButton( icon: const Icon(Icons.filter_list), onPressed: () async { final Map? selectedFilter = await showModalBottomSheet>( isScrollControlled: true, backgroundColor: Colors.transparent, context: context, builder: (context) { return GestureDetector( onTap: () => Navigator.of(context).pop(), child: Container( color: Colors.transparent, child: GestureDetector( onTap: () {}, child: OptModalWidget( defaultPersonType: selectedTypeSubject.value['personType'] ?? '.*', ), ), ), ); }); if (selectedFilter != null) { _updateProvisionalScheduleHistoryAction(selectedFilter); } }, ), ), ], ); } void _updateProvisionalScheduleHistoryAction(Map newType) { if (!_isSubjectClosed) { final currentType = selectedTypeSubject.value; final updatedType = Map.from(currentType); bool needsUpdate = false; newType.forEach((key, newValue) { if (currentType[key] != newValue) { updatedType[key] = newValue; needsUpdate = true; } }); if (needsUpdate) { selectedTypeSubject.add(updatedType); fetchCardListViewService(updatedType); safeSetState(() {}); } } } Future fetchProvisionalScheduleHistoryService() async { try { setState(() => _loading = true); var response = await PhpGroup.getProvSchedules.call( _pageNumber.toString() ); final List ProvisionalScheduleHistory = response.jsonBody['agendamento']['value'] ?? []; List filteredAccess = ProvisionalScheduleHistory.where((item) { final personTypeMatches = _personType == '.*' || item["AGP_STATUS"].toString() == _personType; return personTypeMatches; }).toList(); if (filteredAccess.isNotEmpty) { setState(() { _accessWrap.addAll(filteredAccess); _hasData = true; _loading = false; }); return response; } _showNoMoreDataSnackbar(context); setState(() { _hasData = false; _loading = false; }); return null; } catch (e, s) { await DialogUtil.errorDefault(context); LogUtil.requestAPIFailed('processRequest', "", "Busca Acesso", e, s); setState(() { _hasData = false; _loading = false; }); } return null; } void _showNoMoreDataSnackbar(BuildContext context) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( FFLocalizations.of(context).getVariableText(ptText: "Não há mais dados.", enText: "No more data."), style: TextStyle( color: Colors.white, fontSize: LimitedFontSizeUtil.getBodyFontSize(context), ), ), duration: const Duration(seconds: 3), backgroundColor: FlutterFlowTheme.of(context).primary, ), ); } Widget _body(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ if (_hasData == false && _pageNumber <= 1 && _loading == false) Expanded( child: Column( mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.max, children: [ Center( child: Text( FFLocalizations.of(context) .getVariableText(ptText: "Nenhum histórico encontrado!", enText: "No history found!"), )), ], ), ) else if (_hasData || _pageNumber >= 1) Expanded(child: _cardListViewOrganismWidget()), if (_hasData == true && _loading) Container( padding: const EdgeInsets.only(top: 15, bottom: 15), child: Center( child: CircularProgressIndicator( valueColor: AlwaysStoppedAnimation( FlutterFlowTheme.of(context).primary, ), ), ), ) ], ); } void _loadMoreAccess() { if (_hasData == true) { _pageNumber++; _accessFuture = fetchProvisionalScheduleHistoryService(); } } void fetchCardListViewService(Map select) { _personType = select['personType']!; _accessWrap = []; _pageNumber = 1; _accessFuture = fetchProvisionalScheduleHistoryService(); } Widget _cardListViewOrganismWidget() { return FutureBuilder( future: _accessFuture, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting && _accessWrap.isEmpty) { return Center( child: SizedBox( width: 50.0, height: 50.0, child: SpinKitCircle( color: FlutterFlowTheme.of(context).primary, size: 50.0, ), ), ); } else if (snapshot.hasError) { return Center( child: Text(FFLocalizations.of(context) .getVariableText(ptText: "Falha ao efetuar operação!", enText: "Failed to perform operation!")), ); } return ListView.builder( shrinkWrap: true, physics: const BouncingScrollPhysics(), controller: _scrollController, itemCount: _accessWrap.length, itemBuilder: (context, index) { final ProvisionalScheduleHistoryItem = _accessWrap[index]; return _ProvisionalScheduleHistoryCardMoleculeWidget(context, ProvisionalScheduleHistoryItem); }, ); }, ); } Widget _ProvisionalScheduleHistoryCardMoleculeWidget(BuildContext context, dynamic ProvisionalScheduleHistoryItem) { return CardItemTemplateComponentWidget( imagePath: 'https://freaccess.com.br/freaccess/getImage.php?cliID=${_model.cliUUID}&atividade=getFoto&Documento=${ProvisionalScheduleHistoryItem['PES_ID'] ?? ''}&tipo=${ProvisionalScheduleHistoryItem['PES_TIPO'] ?? ''}', labelsHashMap: Map.from({ FFLocalizations.of(context).getVariableText( ptText: 'Nome:', enText: 'Name:', ): ProvisionalScheduleHistoryItem['AGP_NOME'] ?? '', FFLocalizations.of(context).getVariableText( ptText: 'Acesso:', enText: 'Access:', ): ProvisionalScheduleHistoryItem['AGP_DT_VISITA'] ?? '', FFLocalizations.of(context).getVariableText( ptText: 'Setor', enText: 'Sector', ): ProvisionalScheduleHistoryItem['AGP_OBSERVACAO'] ?? '', }), statusHashMap: [ ProvisionalScheduleHistoryItem['AGP_STATUS'] == 'AT' ? Map.from({ FFLocalizations.of(context).getVariableText( ptText: 'Morador', enText: 'Resident', ): FlutterFlowTheme.of(context).alternate2, }) : ProvisionalScheduleHistoryItem['AGP_STATUS'] == 'IN' ? Map.from({ FFLocalizations.of(context).getVariableText( ptText: 'Visitante', enText: 'Visitor', ): FlutterFlowTheme.of(context).alternate2, }) : Map.from({ FFLocalizations.of(context).getVariableText( ptText: 'Desconhecido', enText: 'Unknown', ): FlutterFlowTheme.of(context).alternate2, }), ProvisionalScheduleHistoryItem['AGP_STATUS'] == 'CO' ? Map.from({ FFLocalizations.of(context).getVariableText( ptText: 'Entrada', enText: 'Entrance', ): FlutterFlowTheme.of(context).success, }) : ProvisionalScheduleHistoryItem['AGP_STATUS'] == 'AA' ? Map.from({ FFLocalizations.of(context).getVariableText( ptText: 'Saída', enText: 'Exit', ): FlutterFlowTheme.of(context).error, }) : Map.from({ FFLocalizations.of(context).getVariableText( ptText: 'Desconhecido', enText: 'Unknown', ): FlutterFlowTheme.of(context).warning, }) ], onTapCardItemAction: () async {}); } String imageUrlAtomWidget(String document, String type) { return valueOrDefault( "https://freaccess.com.br/freaccess/getImage.php?&cliID=${_model.cliUUID}&atividade=getFoto&Documento=$document&tipo=$type", "https://storage.googleapis.com/flutterflow-io-6f20.appspot.com/projects/flutter-freaccess-hub-0xgz9q/assets/7ftdetkzc3s0/360_F_64676383_LdbmhiNM6Ypzb3FM4PPuFP9rHe7ri8Ju.jpg", ); } }