From b678ed514294e0d643d248a057d290af270e3212 Mon Sep 17 00:00:00 2001 From: Ivan Antunes Date: Mon, 12 Aug 2024 13:02:27 -0300 Subject: [PATCH] =?UTF-8?q?fix:=20Pagina=C3=A7=C3=A3o=20do=20Historico=20d?= =?UTF-8?q?e=20Acesso?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/backend/api_requests/api_calls.dart | 62 ++-- .../acess_history_page_model.dart | 6 +- .../acess_history_page_widget.dart | 290 +++++++++--------- 3 files changed, 173 insertions(+), 185 deletions(-) diff --git a/lib/backend/api_requests/api_calls.dart b/lib/backend/api_requests/api_calls.dart index 2a8838ec..1649576f 100644 --- a/lib/backend/api_requests/api_calls.dart +++ b/lib/backend/api_requests/api_calls.dart @@ -1715,7 +1715,7 @@ class RespondeSolicitacaoCall { } class GetAccessCall { - Stream call({ + Future call({ String? devUUID = '', String? userUUID = '', String? cliID = '', @@ -1725,43 +1725,31 @@ class GetAccessCall { String? pesTipo = '', }) { final baseUrl = PhpGroup.getBaseUrl(); - final StreamController controller = StreamController(); - Future.microtask(() async { - try { - final response = await ApiManager.instance.makeApiCall( - callName: 'getAccess', - apiUrl: '$baseUrl/processRequest.php', - callType: ApiCallType.POST, - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - }, - params: { - 'devUUID': devUUID, - 'userUUID': userUUID, - 'cliID': cliID, - 'atividade': atividade, - 'pageSize': pageSize, - 'pageNumber': pageNumber, - 'pesTipo': pesTipo, - }, - bodyType: BodyType.X_WWW_FORM_URL_ENCODED, - returnBody: true, - encodeBodyUtf8: false, - decodeUtf8: false, - cache: false, - isStreamingApi: false, - alwaysAllowBody: false, - ); - controller.add(response); - await controller.close(); - } catch (e) { - controller.addError(e); - await controller.close(); - } - }); - - return controller.stream; + return ApiManager.instance.makeApiCall( + callName: 'getAccess', + apiUrl: '$baseUrl/processRequest.php', + callType: ApiCallType.POST, + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + params: { + 'devUUID': devUUID, + 'userUUID': userUUID, + 'cliID': cliID, + 'atividade': atividade, + 'pageSize': pageSize, + 'pageNumber': pageNumber, + 'pesTipo': pesTipo, + }, + 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( diff --git a/lib/pages/acess_history_page/acess_history_page_model.dart b/lib/pages/acess_history_page/acess_history_page_model.dart index 4d633ac2..ea6e2115 100644 --- a/lib/pages/acess_history_page/acess_history_page_model.dart +++ b/lib/pages/acess_history_page/acess_history_page_model.dart @@ -11,11 +11,11 @@ import 'package:hub/pages/liberation_history/liberation_history_model.dart'; class AcessHistoryPageModel extends FlutterFlowModel { final unfocusNode = FocusNode(); - final _accessHistoryManager = StreamRequestManager(); - Stream accessHistory({ + final _accessHistoryManager = FutureRequestManager(); + Future accessHistory({ String? uniqueQueryKey, bool? overrideCache, - required Stream Function() requestFn, + required Future Function() requestFn, }) => _accessHistoryManager.performRequest( uniqueQueryKey: uniqueQueryKey, diff --git a/lib/pages/acess_history_page/acess_history_page_widget.dart b/lib/pages/acess_history_page/acess_history_page_widget.dart index ddd65809..4fa801d7 100644 --- a/lib/pages/acess_history_page/acess_history_page_widget.dart +++ b/lib/pages/acess_history_page/acess_history_page_widget.dart @@ -1,5 +1,6 @@ import 'dart:developer'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_spinkit/flutter_spinkit.dart'; import 'package:google_fonts/google_fonts.dart'; @@ -7,9 +8,7 @@ import 'package:hub/app_state.dart'; import 'package:hub/backend/api_requests/api_calls.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/components/molecular_components/option_selection_modal/option_selection_modal_widget.dart'; import 'package:hub/components/templates_components/card_item_template_component/card_item_template_component_widget.dart'; -import 'package:hub/flutter_flow/custom_functions.dart'; import 'package:hub/flutter_flow/flutter_flow_icon_button.dart'; import 'package:hub/flutter_flow/flutter_flow_model.dart'; @@ -17,6 +16,8 @@ import 'package:hub/flutter_flow/flutter_flow_theme.dart'; import 'package:hub/flutter_flow/flutter_flow_util.dart'; import 'package:hub/flutter_flow/internationalization.dart'; import 'package:hub/pages/acess_history_page/acess_history_page_model.dart'; +import 'package:hub/shared/utils/dialog_util.dart'; +import 'package:hub/shared/utils/log_util.dart'; import 'package:rxdart/rxdart.dart'; @immutable @@ -53,19 +54,34 @@ class _AcessHistoryPageWidgetState extends State { bool _isSubjectClosed = false; final scaffoldKey = GlobalKey(); - _AcessHistoryPageWidgetState(Map opt) - : selectedTypeSubject = BehaviorSubject.seeded(opt) { - selectedTypeSubject.listen((value) { - log("selectedTypeSubject changed: $value"); - }); + late ScrollController _scrollController; + int _pageNumber = 1; + final int _pageSize = 10; + bool _hasData = false; + bool _loading = false; + + String _personType = '.*'; + String _accessType = '.*'; + String _search = '.*'; + + late Future _accessFuture; + List _accessWrap = []; + + _AcessHistoryPageWidgetState(Map opt) : selectedTypeSubject = BehaviorSubject.seeded(opt) { + selectedTypeSubject.listen((value) {}); } @override void initState() { super.initState(); - _model = createModel(context, () => AcessHistoryPageModel()); - log("initState called in _AcessHistoryPageWidgetState"); + _accessFuture = fetchAccessHistoryService(); + + _scrollController = ScrollController()..addListener(() { + if (_scrollController.position.atEdge && _scrollController.position.pixels != 0) { + _loadMoreAccess(); + } + }); } @override @@ -77,31 +93,31 @@ class _AcessHistoryPageWidgetState extends State { @override Widget build(BuildContext context) { + final theme = FlutterFlowTheme.of(context); + return Scaffold( key: scaffoldKey, backgroundColor: FlutterFlowTheme.of(context).primaryBackground, - appBar: _appBarOrganismWidget(context), - body: _accessHistoryListOrganismWidget(context)); + appBar: _appBar(context, theme), + body: _body(context)); } -// AppBar Widgets - PreferredSizeWidget _appBarOrganismWidget(BuildContext context) { - final theme = FlutterFlowTheme.of(context); + + PreferredSizeWidget _appBar(BuildContext context, FlutterFlowTheme theme) { return AppBar( backgroundColor: theme.primaryBackground, automaticallyImplyLeading: false, - leading: _appBarBackButtonAtomWidget(context, theme), - title: _appBarTitleMoleculeWidget(context, theme), + leading: _backButton(context, theme), + title: _title(context, theme), centerTitle: true, elevation: 0.0, actions: [ - _appBarFilterButtonAtomWidget(context), + _filterButton(context) ], ); } - Widget _appBarBackButtonAtomWidget( - BuildContext context, FlutterFlowTheme theme) { + Widget _backButton(BuildContext context, FlutterFlowTheme theme) { return FlutterFlowIconButton( borderColor: Colors.transparent, borderRadius: 30.0, @@ -116,8 +132,7 @@ class _AcessHistoryPageWidgetState extends State { ); } - Widget _appBarTitleMoleculeWidget( - BuildContext context, FlutterFlowTheme theme) { + Widget _title(BuildContext context, FlutterFlowTheme theme) { return Text( FFLocalizations.of(context).getText('ch8qymga'), style: theme.headlineMedium.override( @@ -126,13 +141,12 @@ class _AcessHistoryPageWidgetState extends State { fontSize: 16.0, letterSpacing: 0.0, useGoogleFonts: - GoogleFonts.asMap().containsKey(theme.headlineMediumFamily), + GoogleFonts.asMap().containsKey(theme.headlineMediumFamily), ), ); } - Widget _appBarFilterButtonAtomWidget(BuildContext context) { - log('selectedTypeSubject: ${selectedTypeSubject.value}'); + Widget _filterButton(BuildContext context) { return Row( mainAxisAlignment: MainAxisAlignment.end, children: [ @@ -141,27 +155,20 @@ class _AcessHistoryPageWidgetState extends State { child: IconButton( icon: const Icon(Icons.filter_list), onPressed: () async { - final Map? selectedFilter = - await showModalBottomSheet>( + final Map? selectedFilter = await showModalBottomSheet>( isScrollControlled: true, backgroundColor: Colors.transparent, context: context, builder: (context) { return GestureDetector( - onTap: () { - Navigator.of(context).pop(); - }, + onTap: () => Navigator.of(context).pop(), child: Container( color: Colors.transparent, child: GestureDetector( onTap: () {}, child: OptModalWidget( - defaultAccessType: - selectedTypeSubject.value['accessType'] ?? - '.*', - defaultPersonType: - selectedTypeSubject.value['personType'] ?? - '.*', + defaultAccessType: selectedTypeSubject.value['accessType'] ?? '.*', + defaultPersonType: selectedTypeSubject.value['personType'] ?? '.*', ), ), ), @@ -169,7 +176,6 @@ class _AcessHistoryPageWidgetState extends State { }); if (selectedFilter != null) { - log('Selected Filter: $selectedFilter'); _updateAccessHistoryAction(selectedFilter); } }, @@ -192,108 +198,112 @@ class _AcessHistoryPageWidgetState extends State { }); if (needsUpdate) { selectedTypeSubject.add(updatedType); - log("updateAccessHistory called with newType: $newType"); + fetchCardListViewService(updatedType); safeSetState(() {}); } } } - Stream fetchAccessHistoryService(String selectedType) { - log('Calling API with type: $selectedType'); - switch (selectedType) { - case 'E': - return _model.accessHistory( - requestFn: () => PhpGroup.getAccessCall.call( - devUUID: FFAppState().devUUID, - userUUID: FFAppState().userUUID, - cliID: FFAppState().cliUUID, - atividade: 'getAcessos', - pageSize: '100', - pageNumber: '1', - pesTipo: 'E', - ), - ); - case 'O': - return _model.accessHistory( - requestFn: () => PhpGroup.getAccessCall.call( - devUUID: FFAppState().devUUID, - userUUID: FFAppState().userUUID, - cliID: FFAppState().cliUUID, - atividade: 'getAcessos', - pageSize: '100', - pageNumber: '1', - pesTipo: 'O', - ), - ); - default: - return _model.accessHistory( - requestFn: () => PhpGroup.getAccessCall.call( - devUUID: FFAppState().devUUID, - userUUID: FFAppState().userUUID, - cliID: FFAppState().cliUUID, - atividade: 'getAcessos', - pageSize: '100', - pageNumber: '1', - pesTipo: 'T', - ), - ); + Future fetchAccessHistoryService() async { + try { + setState(() => _loading = true); + var response = await PhpGroup.getAccessCall.call( + devUUID: FFAppState().devUUID, + userUUID: FFAppState().userUUID, + cliID: FFAppState().cliUUID, + atividade: 'getAcessos', + pageSize: _pageSize.toString(), + pageNumber: _pageNumber.toString(), + pesTipo: _personType != 'E' && _personType != 'O' ? 'T' : _personType, + ); + + final List accessHistory = response.jsonBody['acessos'] ?? []; + + List filteredAccess = accessHistory.where((item) { + final personTypeMatches = _personType == '.*' || item["PES_TIPO"].toString() == _personType; + final accessTypeMatches = _accessType == '.*' || item["ACE_TIPO"].toString() == _accessType; + final searchMatches = _search == '.*' || item["PES_NOME"].toString().toLowerCase().contains(_search.toLowerCase()); + return personTypeMatches && accessTypeMatches && searchMatches; + }).toList(); + + if (filteredAccess != null && filteredAccess.isNotEmpty) { + setState(() { + _accessWrap.addAll(filteredAccess); + _hasData = true; + _loading = false; + }); + return response; + } + + setState(() { + _hasData = false; + _loading = false; + }); + return null; + } catch (e, s) { + DialogUtil.errorDefault(context); + LogUtil.requestAPIFailed('processRequest', "", "Busca Acesso", e, s); + setState(() { + _hasData = false; + _loading = false; + }); } } - Widget _accessHistoryListOrganismWidget(BuildContext context) { - return Center( - child: SingleChildScrollView( - child: Column( - children: [ - StreamBuilder>( - stream: selectedTypeSubject.stream, - builder: (context, snapshot) { - if (!snapshot.hasData) { - return Center(child: CircularProgressIndicator()); - } - final selected = snapshot.data!; - return _cardListViewOrganismWidget(selected); - }, + Widget _body(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded(child: _cardListViewOrganismWidget()), + if (_loading) Container( + padding: const EdgeInsets.only(top: 15, bottom: 15), + color: FlutterFlowTheme.of(context).primary, + child: Center( + child: CircularProgressIndicator( + valueColor: AlwaysStoppedAnimation( + FlutterFlowTheme.of(context).info, + ), ), - ], + ), ), - ), + if (_hasData == false) Container( + padding: const EdgeInsets.only(top: 15, bottom: 15), + color: FlutterFlowTheme.of(context).primary, + child: Center( + child: Text( + FFLocalizations.of(context).getVariableText( + ptText: "Não há mais dados.", + enText: "No more data." + ), + style: TextStyle(color: FlutterFlowTheme.of(context).info), + ) + ), + ), + ], ); } - Future> fetchCardListViewService( - Map select) async { - log('Fetching access history'); - final response = - await fetchAccessHistoryService(select['personType']!).first; - log('Response: ${response.jsonBody}'); - final List accessHistory = response.jsonBody['acessos'] ?? []; - log('Access History Before Filtering: $accessHistory'); - log('Filtering for: Person Type - ${select['personType']}, Access Type - ${select['accessType']}, Search - ${select['search']}'); - - return accessHistory.where((item) { - final personTypeMatches = select['personType'] == '.*' || - item["PES_TIPO"].toString() == select['personType']; - final accessTypeMatches = select['accessType'] == '.*' || - item["ACE_TIPO"].toString() == select['accessType']; - final searchMatches = select['search'] == '.*' || - item["PES_NOME"] - .toString() - .toLowerCase() - .contains(select['search']!.toLowerCase()); - log('NOMES: ${item["PES_NOME"].toString().toLowerCase()}'); - return personTypeMatches && accessTypeMatches && searchMatches; - }).toList(); + void _loadMoreAccess() { + if (_hasData == true) { + _pageNumber++; + _accessFuture = fetchAccessHistoryService(); + } } - Widget _cardListViewOrganismWidget(Map selected) { - log('Selected types in Card: ${selected['personType']}, ${selected['accessType']}'); - log('_buildAccessHistoryList called'); - return FutureBuilder>( - future: fetchCardListViewService(selected), + void fetchCardListViewService(Map select) { + _personType = select['personType']!; + _accessType = select['accessType']!; + _search = select['search']!; + _accessWrap = []; + _pageNumber = 1; + _accessFuture = fetchAccessHistoryService(); + } + + Widget _cardListViewOrganismWidget() { + return FutureBuilder( + future: _accessFuture, builder: (context, snapshot) { - if (snapshot.connectionState == ConnectionState.waiting) { - log('Waiting for data'); + if (snapshot.connectionState == ConnectionState.waiting && _accessWrap.isEmpty) { return Center( child: SizedBox( width: 50.0, @@ -304,40 +314,30 @@ class _AcessHistoryPageWidgetState extends State { ), ), ); - } else if (snapshot.hasData && snapshot.data!.isEmpty) { - return Center( - child: Text(FFLocalizations.of(context).getVariableText( - ptText: "Nenhum histórico encontrado!", - enText: "No history found!")), - ); } else if (snapshot.hasError) { return Center( child: Text(FFLocalizations.of(context).getVariableText( ptText: "Falha ao efetuar operação!", enText: "Failed to perform operation!")), ); - } else { - final accessHistory = snapshot.data!; - log('Access History: $accessHistory'); - return ListView.builder( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemCount: accessHistory.length, - itemBuilder: (context, index) { - final accessHistoryItem = accessHistory[index]; - log('Access History Item: ${accessHistoryItem['PES_TIPO']}'); - return _accessHistoryCardMoleculeWidget( - context, accessHistoryItem); - }, - ); } + + return ListView.builder( + shrinkWrap: true, + physics: const BouncingScrollPhysics(), + controller: _scrollController, + itemCount: _accessWrap.length, + itemBuilder: (context, index) { + final accessHistoryItem = _accessWrap[index]; + return _accessHistoryCardMoleculeWidget(context, accessHistoryItem); + }, + ); }, ); } - Widget _accessHistoryCardMoleculeWidget( - BuildContext context, dynamic accessHistoryItem) { - log('Access History Item: $accessHistoryItem'); + Widget _accessHistoryCardMoleculeWidget(BuildContext context, dynamic accessHistoryItem) { + return CardItemTemplateComponentWidget( imageHashMap: Map.from({ 'key': accessHistoryItem['PES_ID'] ?? '',