This commit is contained in:
jantunesmessias 2025-02-07 16:50:45 -03:00
parent 16f43bbab8
commit 906fbcaf24
4 changed files with 141 additions and 108 deletions

View File

@ -52,6 +52,7 @@ class _AccessHistoryState extends State<AccessHistoryScreen> {
_model = createModel(context, () => AcessHistoryPageModel()); _model = createModel(context, () => AcessHistoryPageModel());
_accessFuture = fetchAccessHistoryService(); _accessFuture = fetchAccessHistoryService();
_scrollController = ScrollController() _scrollController = ScrollController()
..addListener(() { ..addListener(() {
if (_scrollController.position.atEdge && if (_scrollController.position.atEdge &&

View File

@ -4,21 +4,24 @@ part of 'vehicles_on_the_property.dart';
// ignore: must_be_immutable // ignore: must_be_immutable
class VehicleHistoryScreen extends StatefulWidget { class VehicleHistoryScreen extends StatefulWidget {
VehicleHistoryScreen(this.model, {super.key}); VehicleHistoryScreen(this.model, {super.key});
late VehicleModel model; late VehicleModel model;
@override @override
State<VehicleHistoryScreen> createState() => _VehicleHistoryScreenState(); State<VehicleHistoryScreen> createState() => _VehicleHistoryScreenState();
} }
class _VehicleHistoryScreenState extends State<VehicleHistoryScreen> class _VehicleHistoryScreenState extends State<VehicleHistoryScreen>
with Remotable { with Remotable {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_initializeScrollController(); _initializeScrollController();
_future = _fetch();
} }
@override @override
@ -69,8 +72,8 @@ class _VehicleHistoryScreenState extends State<VehicleHistoryScreen>
Widget _buildHistoryList(BuildContext context, double limitedBodyTextSize) { Widget _buildHistoryList(BuildContext context, double limitedBodyTextSize) {
return Expanded( return Expanded(
child: FutureBuilder<List<Widget?>>( child: FutureBuilder<List<dynamic>>(
future: _future, future: _fetch(),
builder: (context, snapshot) { builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) { if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator()); return Center(child: CircularProgressIndicator());
@ -79,17 +82,13 @@ class _VehicleHistoryScreenState extends State<VehicleHistoryScreen>
} else { } else {
return ListView.builder( return ListView.builder(
shrinkWrap: true, shrinkWrap: true,
addAutomaticKeepAlives: true,
restorationId: '',
physics: const BouncingScrollPhysics(), physics: const BouncingScrollPhysics(),
controller: _scrollController, controller: _scrollController,
itemCount: _wrap.length + 1, itemCount: snapshot.data!.length ,
itemBuilder: (context, index) { itemBuilder: (context, index) => _generateItems(context, snapshot.data![index], index),
if (index == 0) {
return _buildHeader(context, limitedBodyTextSize);
} else {
Widget? item = _wrap[index - 1];
return _wrap[index - 1] ?? SizedBox.shrink();
}
},
); );
} }
}, },
@ -97,24 +96,6 @@ class _VehicleHistoryScreenState extends State<VehicleHistoryScreen>
); );
} }
Widget _buildHeader(BuildContext context, double limitedBodyTextSize) {
log('amountRegister: ${widget.model.amountRegister}');
return Padding(
padding: const EdgeInsets.only(right: 30, top: 10),
child: Text(
(widget.model.amountRegister == '0' ||
widget.model.amountRegister == null)
? ''
: "${FFLocalizations.of(context).getVariableText(ptText: "Quantidade de Veículos: ", enText: "Amount of Vehicles: ")}${widget.model.amountRegister}/${widget.count}",
textAlign: TextAlign.right,
style: TextStyle(
fontFamily: 'Nunito',
fontSize: limitedBodyTextSize,
),
),
);
}
Widget _buildLoadingIndicator(BuildContext context) { Widget _buildLoadingIndicator(BuildContext context) {
return Container( return Container(
padding: const EdgeInsets.only(top: 15, bottom: 15), padding: const EdgeInsets.only(top: 15, bottom: 15),
@ -127,56 +108,59 @@ class _VehicleHistoryScreenState extends State<VehicleHistoryScreen>
), ),
); );
} }
} }
// Mixin for Fetch Visits
mixin Remotable on State<VehicleHistoryScreen> { mixin Remotable on State<VehicleHistoryScreen> {
late Future<List<Widget?>> _future;
List<Widget?> _wrap = []; late ScrollController _scrollController;
double offset = 0.0;
List<dynamic> _wrap = [];
int _pageNumber = 1; int _pageNumber = 1;
bool _hasData = true; bool _hasData = true;
bool _loading = true; bool _loading = true;
int count = 0; int count = 0;
Future<List<dynamic>> _fetch() async {
Future<List<Widget?>> _fetch() async { if (!_hasData || !_loading) return _wrap;
if (!widget._hasData || !widget._loading) return []; print('hasHasData');
setState(() => _loading = true);
setState(() => widget._loading = true);
try { try {
var response = await PhpGroup.getVehiclesByProperty.call(widget._pageNumber.toString());
final List<dynamic> vehicles = response.jsonBody['vehicles'] as List<dynamic>? ?? [];
safeSetState(() => widget.count = response.jsonBody['total_rows'] ?? 0);
var response = await PhpGroup.getVehiclesByProperty.call(_pageNumber.toString());
final List<dynamic> vehicles = response.jsonBody['vehicles'] as List<dynamic>? ?? [];
safeSetState(() => count = response.jsonBody['total_rows'] ?? 0);
if (vehicles.isNotEmpty) { if (vehicles.isNotEmpty) {
setState(() { setState(() {
_hasData = true;
widget._hasData = true; _loading = false;
widget._loading = false;
}); });
print('vehicles.isNotEmpty');
_wrap.addAll(vehicles);
return _generateItems(context, vehicles); return _wrap;
} }
_showNoMoreDataSnackBar(context); _showNoMoreDataSnackBar(context);
setState(() { setState(() {
widget._hasData = false; _hasData = false;
widget._loading = false; _loading = false;
}); });
return []; print('hasEmpty: ${_wrap.length}');
return _wrap;
} catch (e, s) { } catch (e, s) {
DialogUtil.errorDefault(context); DialogUtil.errorDefault(context);
LogUtil.requestAPIFailed("proccessRequest.php", "", "Consulta de Veículo", e, s); LogUtil.requestAPIFailed("proccessRequest.php", "", "Consulta de Veículo", e, s);
setState(() { setState(() {
widget._hasData = false; _hasData = false;
widget._loading = false; _loading = false;
}); });
return []; print('hasError');
return _wrap;
} }
} }
@ -189,43 +173,56 @@ mixin Remotable on State<VehicleHistoryScreen> {
showSnackbar(context, message, true); showSnackbar(context, message, true);
} }
Future<List<Widget?>> _generateItems(BuildContext context, List<dynamic> uItem) async { Widget _buildHeader(BuildContext context) {
if (!widget._hasData) return []; double limitedBodyTextSize = LimitedFontSizeUtil.getBodyFontSize(context);
log('amountRegister: ${widget.model.amountRegister}');
return Padding(
padding: const EdgeInsets.only(right: 30, top: 10),
child: Text(
(widget.model.amountRegister == '0' ||
widget.model.amountRegister == null)
? ''
: "${FFLocalizations.of(context).getVariableText(ptText: "Quantidade de Veículos: ", enText: "Amount of Vehicles: ")}${widget.model.amountRegister}/$count",
textAlign: TextAlign.right,
style: TextStyle(
fontFamily: 'Nunito',
fontSize: limitedBodyTextSize,
),
),
);
}
List<Widget?> items = []; Widget? _generateItems(BuildContext context, dynamic snapshot, int index) {
if (index == 0) return _buildHeader(context);
for (var uItem in uItem) { final bool? isOwner = snapshot['isOwnerVehicle'];
final bool? isOwner = uItem['isOwnerVehicle']; final IconData? iconData = isOwner == true ? Symbols.garage : Symbols.directions_car;
final IconData? iconData = isOwner == true ? Symbols.no_crash : Symbols.directions_car;
final FreCardIcon? cardIcon = isOwner != null final FreCardIcon? cardIcon = isOwner != null
? FreCardIcon(height: 50, width: 100, icon: Icon(iconData, size: 80, opticalSize: 10)) ? FreCardIcon(height: 50, width: 100, icon: Icon(iconData, size: 80, opticalSize: 10))
: null; : null;
final String? tag = uItem['tag']; final String? tag = snapshot['tag'];
final bool containTag = tag.isNotNullAndEmpty; final bool containTag = tag.isNotNullAndEmpty;
final Map<String, String> labelsHashMap = _generateLabelsHashMap(context, uItem, tag, containTag); final Map<String, String> labelsHashMap = _generateLabelsHashMap(context, snapshot, tag, containTag);
final statusHashMapList = await _generateStatusHashMapList(uItem); final List<Map<String, Color>> statusHashMapList = _generateStatusHashMapList(snapshot);
Future<void> onTapCardItemAction() async { Future<void> onTapCardItemAction() async {
await _handleCardItemTap(context, cardIcon, uItem); _handleCardItemTap(context, cardIcon, snapshot);
} }
final statusLinkedHashMap = statusHashMapList.map((map) => LinkedHashMap<String, Color>.from(map)).toList(); final statusLinkedHashMap = statusHashMapList.map((map) => LinkedHashMap<String, Color>.from(map)).toList();
final length = statusLinkedHashMap.expand((e) => [e.length]); final length = statusLinkedHashMap.expand((e) => [e.length]);
items.add(CardItemTemplateComponentWidget( return CardItemTemplateComponentWidget(
icon: cardIcon, icon: cardIcon,
labelsHashMap: labelsHashMap, labelsHashMap: labelsHashMap,
statusHashMap: statusHashMapList, statusHashMap: statusHashMapList,
onTapCardItemAction: onTapCardItemAction, onTapCardItemAction: onTapCardItemAction,
itemWidthFactor: length == 1 ? 0.25 : 0.50, itemWidthFactor: length == 1 ? 0.25 : 0.50,
)); );
} }
widget._wrap.addAll(items);
return items;
}
Map<String, String> _generateLabelsHashMap(BuildContext context, Map<String, String> _generateLabelsHashMap(BuildContext context,
Map<String, dynamic> uItem, String? tag, bool containTag) { Map<String, dynamic> uItem, String? tag, bool containTag) {
@ -242,17 +239,17 @@ mixin Remotable on State<VehicleHistoryScreen> {
}; };
} }
Future<List<Map<String, Color>>> _generateStatusHashMapList( List<Map<String, Color>> _generateStatusHashMapList(
Map<String, dynamic> uItem) async { Map<String, dynamic> uItem) {
final statusHashMap = final statusHashMap =
await widget.model.generateStatusColorMap(uItem, false); widget.model.generateStatusColorMap(uItem, false);
return statusHashMap != null ? [statusHashMap] : []; return statusHashMap != null ? [statusHashMap] : [];
} }
Future<void> _handleCardItemTap(BuildContext context, FreCardIcon? cardIcon, Future<void> _handleCardItemTap(BuildContext context, FreCardIcon? cardIcon,
Map<String, dynamic> uItem) async { Map<String, dynamic> uItem) async {
try { try {
final dialogContent = await widget.model.buildVehicleDetails( final dialogContent = widget.model.buildVehicleDetails(
icon: cardIcon, icon: cardIcon,
item: uItem, item: uItem,
context: context, context: context,
@ -266,9 +263,8 @@ mixin Remotable on State<VehicleHistoryScreen> {
Dialog(alignment: Alignment.center, child: dialogContent), Dialog(alignment: Alignment.center, child: dialogContent),
).whenComplete(() { ).whenComplete(() {
safeSetState(() { safeSetState(() {
widget._pageNumber = 1; _pageNumber = 1;
widget._wrap = []; _fetch();
widget._future = _fetch();
}); });
}); });
} catch (e, s) { } catch (e, s) {
@ -276,31 +272,34 @@ mixin Remotable on State<VehicleHistoryScreen> {
LogUtil.requestAPIFailed( LogUtil.requestAPIFailed(
"proccessRequest.php", "", "Consulta de Veículos", e, s); "proccessRequest.php", "", "Consulta de Veículos", e, s);
safeSetState(() { safeSetState(() {
widget._hasData = false; _hasData = false;
widget._loading = false; _loading = false;
}); });
} }
} }
late ScrollController _scrollController;
void _initializeScrollController() { void _initializeScrollController() {
_scrollController = ScrollController() _scrollController = ScrollController(keepScrollOffset: true, initialScrollOffset: offset)
..addListener(() { ..addListener(() {
print('ScrollController'); print('ScrollController');
if(!widget._hasData) return; if(!_hasData) return;
if (_scrollController.position.pixels >= _scrollController.position.maxScrollExtent) { if
// (_scrollController.position.pixels >= _scrollController.position.maxScrollExtent)
(_scrollController.position.atEdge && _scrollController.position.pixels != 0)
{
print('ScrollController -> loadMore'); print('ScrollController -> loadMore');
offset = _scrollController.offset;
_loadMore(); _loadMore();
} }
}); });
} }
void _loadMore() { void _loadMore() async {
if (widget._hasData) { if (_hasData) {
widget._pageNumber++; _pageNumber+=1;
widget._loading = true; _loading = true;
widget._future = _fetch(); _fetch();
} }
} }
} }

View File

@ -71,6 +71,7 @@ class VehicleModel extends FlutterFlowModel<VehiclePage>
Future<void> initAsync() async { Future<void> initAsync() async {
amountRegister = amountRegister =
await StorageHelper().get(LocalsStorageKey.vehicleAmountRegister.key); await StorageHelper().get(LocalsStorageKey.vehicleAmountRegister.key);
autoApproval= await StorageHelper().get(LocalsStorageKey.vehicleAutoApproval.key);
} }
bool isFormValid(BuildContext context, GlobalKey<FormState> formKey) { bool isFormValid(BuildContext context, GlobalKey<FormState> formKey) {
@ -89,6 +90,8 @@ mixin class _BaseVehiclePage {
bool isEditing = false; bool isEditing = false;
ApiCallResponse? vehicleResponse; ApiCallResponse? vehicleResponse;
String? amountRegister = '0'; String? amountRegister = '0';
late final String? autoApproval;
VoidCallback? onUpdateVehicle; VoidCallback? onUpdateVehicle;
VoidCallback? onRegisterVehicle; VoidCallback? onRegisterVehicle;
@ -237,10 +240,10 @@ mixin _VehicleUpdateScreenModel on _BaseVehiclePage {
/// [_VehicleHistoryScreenModel] is a mixin that contains the business logic of the vehicle history page. /// [_VehicleHistoryScreenModel] is a mixin that contains the business logic of the vehicle history page.
mixin _VehicleHistoryScreenModel on _BaseVehiclePage { mixin _VehicleHistoryScreenModel on _BaseVehiclePage {
Future<Map<String, Color>?>? generateStatusColorMap(
dynamic uItem, bool isDetail) async {
final autoApproval = Map<String, Color>? generateStatusColorMap(dynamic uItem, bool isDetail) {
await StorageHelper().get(LocalsStorageKey.vehicleAutoApproval.key);
if (autoApproval.toBoolean == true) return null; if (autoApproval.toBoolean == true) return null;
final theme = FlutterFlowTheme.of(context); final theme = FlutterFlowTheme.of(context);
final localization = FFLocalizations.of(context); final localization = FFLocalizations.of(context);
@ -296,7 +299,7 @@ mixin _VehicleHistoryScreenModel on _BaseVehiclePage {
return {}; return {};
} }
Future<List<FFButtonWidget>?> generateActionButtons(dynamic item) async { List<FFButtonWidget> generateActionButtons(dynamic item) {
final Color iconButtonColor = FlutterFlowTheme.of(context).primaryText; final Color iconButtonColor = FlutterFlowTheme.of(context).primaryText;
final FFButtonOptions buttonOptions = FFButtonOptions( final FFButtonOptions buttonOptions = FFButtonOptions(
height: 40, height: 40,
@ -339,7 +342,7 @@ mixin _VehicleHistoryScreenModel on _BaseVehiclePage {
ptText: 'Você tem certeza que deseja cancelar essa solicitação?', ptText: 'Você tem certeza que deseja cancelar essa solicitação?',
enText: 'Are you sure you want to delete this request?', enText: 'Are you sure you want to delete this request?',
), ),
() async => await processCancelRequest(item['status'], item)); () async => processCancelRequest(item['status'], item));
} }
final deleteText = FFLocalizations.of(context) final deleteText = FFLocalizations.of(context)
@ -356,7 +359,7 @@ mixin _VehicleHistoryScreenModel on _BaseVehiclePage {
ptText: 'Você tem certeza que deseja excluir esse veículo?', ptText: 'Você tem certeza que deseja excluir esse veículo?',
enText: 'Are you sure you want to delete this vehicle?', enText: 'Are you sure you want to delete this vehicle?',
), ),
() async => await processDeleteRequest(item), () async => processDeleteRequest(item),
); );
} }
@ -401,7 +404,7 @@ mixin _VehicleHistoryScreenModel on _BaseVehiclePage {
]; ];
} }
Future<void> processDeleteRequest(dynamic item) async { void processDeleteRequest(dynamic item) async {
log('processDeleteRequest -> item[$item]'); log('processDeleteRequest -> item[$item]');
return await PhpGroup.deleteVehicle return await PhpGroup.deleteVehicle
.call( .call(
@ -448,7 +451,7 @@ mixin _VehicleHistoryScreenModel on _BaseVehiclePage {
}); });
} }
Future<void> processCancelRequest(String status, dynamic item) async { void processCancelRequest(String status, dynamic item) async {
late final ApiCallResponse value; late final ApiCallResponse value;
try { try {
switch (status) { switch (status) {
@ -500,7 +503,7 @@ mixin _VehicleHistoryScreenModel on _BaseVehiclePage {
} }
} }
Future<ApiCallResponse> processCancelDeleteRequest(dynamic item) async { Future<ApiCallResponse> processCancelDeleteRequest(dynamic item) async{
return await PhpGroup.deleteVehicle.call( return await PhpGroup.deleteVehicle.call(
vehicleId: item['vehicleId'], vehicleId: item['vehicleId'],
licensePlate: item['licensePlate'], licensePlate: item['licensePlate'],
@ -509,7 +512,7 @@ mixin _VehicleHistoryScreenModel on _BaseVehiclePage {
); );
} }
Future<ApiCallResponse> processCancelUpdateRequest(dynamic item) async { Future<ApiCallResponse> processCancelUpdateRequest(dynamic item) async {
return await PhpGroup.deleteVehicle.call( return await PhpGroup.deleteVehicle.call(
vehicleId: item['vehicleId'], vehicleId: item['vehicleId'],
licensePlate: item['licensePlate'], licensePlate: item['licensePlate'],
@ -527,7 +530,7 @@ mixin _VehicleHistoryScreenModel on _BaseVehiclePage {
); );
} }
Future<Map<String, String>> generateLabelsHashMap(dynamic item) async { Map<String, String> generateLabelsHashMap(dynamic item) {
return { return {
if (item['model'] != null && item['model'] != '') if (item['model'] != null && item['model'] != '')
'${FFLocalizations.of(context).getVariableText(ptText: "Modelo", enText: "Model")}:': '${FFLocalizations.of(context).getVariableText(ptText: "Modelo", enText: "Model")}:':
@ -547,15 +550,15 @@ mixin _VehicleHistoryScreenModel on _BaseVehiclePage {
}; };
} }
Future<Widget> buildVehicleDetails({ DetailsComponentWidget buildVehicleDetails({
required dynamic item, required dynamic item,
required BuildContext context, required BuildContext context,
required VehicleModel model, required VehicleModel model,
required FreCardIcon? icon, required FreCardIcon? icon,
}) async { }) {
final status = await generateStatusColorMap(item, true); final status = generateStatusColorMap(item, true);
final buttons = await generateActionButtons(item); final buttons = generateActionButtons(item);
final labels = await generateLabelsHashMap(item); final labels = generateLabelsHashMap(item);
return DetailsComponentWidget( return DetailsComponentWidget(
icon: icon, icon: icon,
buttons: buttons, buttons: buttons,

30
scripts/httpie.sh Executable file
View File

@ -0,0 +1,30 @@
#!/bin/bash
# Define the base URL for the API endpoint
BASE_URL="https://freaccess.com.br/freaccess/processRequest.php"
# Define common parameters
DEV_UUID="6b7b81849c115a8a"
USER_UUID="678aa05b0c2154.50583237"
CLI_ID="7"
ACTIVITY="getVehiclesByProperty"
PAGE_SIZE="10"
# Function to perform the HTTP request
perform_request() {
local page=$1
http --form POST "$BASE_URL" \
devUUID="$DEV_UUID" \
userUUID="$USER_UUID" \
cliID="$CLI_ID" \
atividade="$ACTIVITY" \
page="$page" \
pageSize="$PAGE_SIZE" \
--check-status \
--ignore-stdin \
--timeout=10
}
# Perform requests for pages 1 and 2
perform_request 1
perform_request 2