wip pageable mixin

This commit is contained in:
jantunesmessias 2025-02-10 15:13:35 -03:00
parent a4b7ee3cd0
commit 7b0297a491
3 changed files with 123 additions and 108 deletions

View File

@ -11,15 +11,18 @@ class VehicleHistoryScreen extends StatefulWidget {
} }
class _VehicleHistoryScreenState extends State<VehicleHistoryScreen> class _VehicleHistoryScreenState extends State<VehicleHistoryScreen>
with Remotable { with Pageable {
final apiCall = PhpGroup.getVehiclesByProperty; final apiCall = PhpGroup.getVehiclesByProperty;
int count = 0;
final PagingController<int, dynamic> _pagingController =
PagingController<int, dynamic>(firstPageKey: 1);
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_pagingController.addPageRequestListener( _pagingController.addPageRequestListener(
(dynamic pageKey) => _fetch( (dynamic pageKey) => fetchPage(
hasData: () async { dataProvider: () async {
final newItems = await apiCall.call(pageKey.toString()); final newItems = await apiCall.call(pageKey.toString());
if (newItems.jsonBody == null) return (false, null); if (newItems.jsonBody == null) return (false, null);
final List<dynamic> vehicles = final List<dynamic> vehicles =
@ -31,27 +34,19 @@ class _VehicleHistoryScreenState extends State<VehicleHistoryScreen>
}); });
return (vehicles.isNotEmpty, vehicles); return (vehicles.isNotEmpty, vehicles);
}, },
onNotHas: () { onDataUnavailable: () {
_showNoMoreDataSnackBar(context); setState(() {});
setState(() { showNoMoreDataSnackBar(context);
// _hasData = false;
// _loading = false;
});
}, },
onHas: (vehicles) { onDataAvailable: (vehicles) {
setState(() { setState(() {});
// _loading = false;
});
_pagingController.appendLastPage(vehicles); _pagingController.appendLastPage(vehicles);
}, },
onError: (e, s) { onFetchError: (e, s) {
DialogUtil.errorDefault(context); DialogUtil.errorDefault(context);
LogUtil.requestAPIFailed( LogUtil.requestAPIFailed(
"proccessRequest.php", "", "Consulta de Veículo", e, s); "proccessRequest.php", "", "Consulta de Veículo", e, s);
setState(() { setState(() {});
// _hasData = false;
// _loading = false;
});
}, },
), ),
); );
@ -92,7 +87,7 @@ class _VehicleHistoryScreenState extends State<VehicleHistoryScreen>
return Column( return Column(
children: [ children: [
_buildHeader(context), _buildHeader(context),
_buildBody(), _buildBody(context),
], ],
); );
} }
@ -117,36 +112,23 @@ class _VehicleHistoryScreenState extends State<VehicleHistoryScreen>
); );
} }
Expanded _buildBody() { Expanded _buildBody(BuildContext context) {
final noDataFound = FFLocalizations.of(context).getVariableText( final noDataFound = FFLocalizations.of(context).getVariableText(
ptText: "Nenhum veículo encontrado!", ptText: "Nenhum veículo encontrado!",
enText: "No vehicle found", enText: "No vehicle found",
); );
return Expanded( return buildPaginatedListView<int, dynamic>(
child: RefreshIndicator( noDataFound,
onRefresh: () async => _pagingController.refresh(), _pagingController,
child: PagedListView<int, dynamic>( _generateItems,
pagingController: _pagingController,
builderDelegate: PagedChildBuilderDelegate<dynamic>(
animateTransitions: true,
itemBuilder: (context, item, index) =>
_generateItems(context, index, item),
// noMoreItemsIndicatorBuilder: ,
newPageProgressIndicatorBuilder: (context) =>
_buildLoadingIndicator(context),
firstPageProgressIndicatorBuilder: (context) =>
_buildLoadingIndicator(context),
noItemsFoundIndicatorBuilder: (context) =>
_buildNoDataFound(context, noDataFound),
firstPageErrorIndicatorBuilder: (context) => const Placeholder(),
newPageErrorIndicatorBuilder: (context) => const Placeholder(),
),
),
),
); );
} }
Widget _generateItems(BuildContext context, int index, dynamic item) { Widget _generateItems(
BuildContext context,
dynamic item,
int index,
) {
log('item: $item'); log('item: $item');
final bool? isOwner = item['isOwnerVehicle']; final bool? isOwner = item['isOwnerVehicle'];
final IconData iconData = final IconData iconData =
@ -249,69 +231,3 @@ class _VehicleHistoryScreenState extends State<VehicleHistoryScreen>
} }
} }
} }
mixin Remotable on State<VehicleHistoryScreen> {
final PagingController<int, dynamic> _pagingController =
PagingController<int, dynamic>(firstPageKey: 1);
double offset = 0.0;
// bool _hasData = true;
// bool _loading = true;
int count = 0;
Future<void> _fetch({
required Future<(bool, dynamic)> Function() hasData,
required void Function(dynamic) onHas,
required void Function() onNotHas,
required void Function(Object, StackTrace) onError,
}) async {
// if (!_hasData || !_loading) return;
try {
final (bool, dynamic) data = await hasData();
if (data.$1)
onHas(data.$2);
else
onNotHas();
} catch (e, s) {
onError(e, s);
}
}
void _showNoMoreDataSnackBar(BuildContext context) {
final message = FFLocalizations.of(context).getVariableText(
ptText: "Não há mais dados.",
enText: "No more data.",
);
showSnackbar(context, message, true);
}
Widget _buildNoDataFound(BuildContext context, String title) {
final headerFontSize = LimitedFontSizeUtil.getHeaderFontSize(context);
// final bodyFontSize = LimitedFontSizeUtil.getBodyFontSize(context);
return Expanded(
child: Center(
child: Text(
title,
style: TextStyle(
fontFamily: 'Nunito',
fontSize: headerFontSize,
),
),
),
);
}
Widget _buildLoadingIndicator(BuildContext context) {
return Container(
padding: const EdgeInsets.symmetric(vertical: 15),
child: Center(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(
FlutterFlowTheme.of(context).primary,
),
),
),
);
}
}

View File

@ -13,6 +13,7 @@ import 'package:hub/features/module/index.dart';
import 'package:hub/flutter_flow/index.dart'; import 'package:hub/flutter_flow/index.dart';
import 'package:hub/pages/vehicles_on_the_property/vehicle_model.dart'; import 'package:hub/pages/vehicles_on_the_property/vehicle_model.dart';
import 'package:hub/shared/extensions/index.dart'; import 'package:hub/shared/extensions/index.dart';
import 'package:hub/shared/mixins/pageable_mixin.dart';
import 'package:hub/shared/utils/dialog_util.dart'; import 'package:hub/shared/utils/dialog_util.dart';
import 'package:hub/shared/utils/license_util.dart'; import 'package:hub/shared/utils/license_util.dart';
import 'package:hub/shared/utils/limited_text_size.dart'; import 'package:hub/shared/utils/limited_text_size.dart';

View File

@ -0,0 +1,98 @@
import 'package:flutter/material.dart';
import 'package:hub/flutter_flow/index.dart';
import 'package:hub/shared/utils/limited_text_size.dart';
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
extension PagedListViewExtension<PageKeyType, ItemType>
on PagedSliverList<PageKeyType, ItemType> {}
mixin Pageable<T extends StatefulWidget> on State<T> {
Expanded buildPaginatedListView<X, Y>(
String noDataFound,
PagingController<X, Y> pg,
Widget Function(BuildContext, Y, int) itemBuilder) {
final theme = FlutterFlowTheme.of(context);
return Expanded(
child: RefreshIndicator(
backgroundColor: theme.primaryBackground,
color: theme.primary,
onRefresh: () async => pg.refresh(),
child: PagedListView<X, Y>(
pagingController: pg,
builderDelegate: PagedChildBuilderDelegate<Y>(
animateTransitions: true,
itemBuilder: (context, item, index) =>
itemBuilder(context, item, index),
// noMoreItemsIndicatorBuilder: ,
newPageProgressIndicatorBuilder: (context) =>
buildLoadingIndicator(context),
firstPageProgressIndicatorBuilder: (context) =>
buildLoadingIndicator(context),
noItemsFoundIndicatorBuilder: (context) =>
buildNoDataFound(context, noDataFound),
firstPageErrorIndicatorBuilder: (context) => const Placeholder(),
newPageErrorIndicatorBuilder: (context) => const Placeholder(),
),
),
),
);
}
Future<void> fetchPage({
required Future<(bool, dynamic)> Function() dataProvider,
required void Function(dynamic data) onDataAvailable,
required void Function() onDataUnavailable,
required void Function(Object error, StackTrace stackTrace) onFetchError,
}) async {
try {
final (bool isDataAvailable, dynamic data) = await dataProvider();
if (isDataAvailable) {
onDataAvailable(data);
} else {
onDataUnavailable();
}
} catch (error, stackTrace) {
onFetchError(error, stackTrace);
}
}
void showNoMoreDataSnackBar(BuildContext context) {
final message = FFLocalizations.of(context).getVariableText(
ptText: "Não há mais dados.",
enText: "No more data.",
);
showSnackbar(context, message, true);
}
Widget buildNoDataFound(BuildContext context, String title) {
final headerFontSize = LimitedFontSizeUtil.getHeaderFontSize(context);
// final bodyFontSize = LimitedFontSizeUtil.getBodyFontSize(context);
return Expanded(
child: Center(
child: Text(
title,
style: TextStyle(
fontFamily: 'Nunito',
fontSize: headerFontSize,
),
),
),
);
}
Widget buildLoadingIndicator(BuildContext context) {
return Container(
padding: const EdgeInsets.symmetric(vertical: 15),
child: Center(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(
FlutterFlowTheme.of(context).primary,
),
),
),
);
}
}