This commit is contained in:
J. A. Messias 2025-01-29 10:27:23 -03:00
parent 3b7a33801f
commit 7dd7ed7a32
14 changed files with 581 additions and 529 deletions

View File

@ -82,7 +82,7 @@ void main() {
// LocalsTest.unlinkLocal(); // LocalsTest.unlinkLocal();
VehicleTest.vehiclePage(); VehicleTest.vehiclePage();
VehicleTest.historyScreen(); // VehicleTest.historyScreen();
VehicleTest.registerScreen(); // VehicleTest.registerScreen();
VehicleTest.updateScreen(); // VehicleTest.updateScreen();
} }

View File

@ -1,7 +1,6 @@
part of 'app_test.dart'; part of 'app_test.dart';
Future<void> _loggedWithMultiLocalsAccount(PatrolIntegrationTester $, Future<void> _loggedWithMultiLocalsAccount(PatrolIntegrationTester $, [bool forceLinkedLocal = true]) async {
[bool forceLinkedLocal = true]) async {
await _init($); await _init($);
await StorageHelper() // await StorageHelper() //
.set(SecureStorageKey.isLogged.value, 'true'); .set(SecureStorageKey.isLogged.value, 'true');
@ -19,18 +18,15 @@ Future<void> _loggedWithMultiLocalsAccount(PatrolIntegrationTester $,
await StorageHelper() // await StorageHelper() //
.set(LocalsStorageKey.isNewVersion.key, true); .set(LocalsStorageKey.isNewVersion.key, true);
if (forceLinkedLocal == true) { if (forceLinkedLocal == true) {
await StorageHelper() // await StorageHelper().set(ProfileStorageKey.clientUUID.key, '7');
.set(ProfileStorageKey.clientUUID.key, '7'); await StorageHelper().set(ProfileStorageKey.ownerUUID.key, '7');
await PhpGroup // await StorageHelper().set(ProfileStorageKey.clientName.key, 'FRE ACCESS DEMO');
.resopndeVinculo await PhpGroup.respondeVinculo.call(tarefa: 'A');
.call(tarefa: 'A'); await LicenseRepositoryImpl().resetLicense();
await LicenseRepositoryImpl() //
.resetLicense();
} }
} }
Future<void> _loggedWithSomeoneLocalAccount(PatrolIntegrationTester $, Future<void> _loggedWithSomeoneLocalAccount(PatrolIntegrationTester $, [bool forceLinkedLocal = true]) async {
[bool forceLinkedLocal = true]) async {
await _init($); await _init($);
await StorageHelper() // await StorageHelper() //
.set(SecureStorageKey.isLogged.value, 'true'); .set(SecureStorageKey.isLogged.value, 'true');
@ -48,13 +44,11 @@ Future<void> _loggedWithSomeoneLocalAccount(PatrolIntegrationTester $,
await StorageHelper() // await StorageHelper() //
.set(LocalsStorageKey.isNewVersion.key, true); .set(LocalsStorageKey.isNewVersion.key, true);
if (forceLinkedLocal == true) { if (forceLinkedLocal == true) {
await StorageHelper() // await StorageHelper().set(ProfileStorageKey.clientUUID.key, '7');
.set(ProfileStorageKey.clientUUID.key, '7'); await StorageHelper().set(ProfileStorageKey.ownerUUID.key, '7');
await PhpGroup // await StorageHelper().set(ProfileStorageKey.clientName.key, 'FRE ACCESS DEMO');
.resopndeVinculo await PhpGroup.respondeVinculo.call(tarefa: 'A');
.call(tarefa: 'A'); await LicenseRepositoryImpl().resetLicense();
await LicenseRepositoryImpl() //
.resetLicense();
} }
} }
@ -101,8 +95,7 @@ Future<void> _navigateToSignUp(PatrolIntegrationTester $) async {
} }
Future<void> _navigateBackUsingSystemGesture() async => Future<void> _navigateBackUsingSystemGesture() async =>
IntegrationTestWidgetsFlutterBinding.instance.keyboard IntegrationTestWidgetsFlutterBinding.instance.keyboard.isLogicalKeyPressed(LogicalKeyboardKey.escape);
.isLogicalKeyPressed(LogicalKeyboardKey.escape);
Future<void> _initializeTracking() async { Future<void> _initializeTracking() async {
print('Requesting tracking authorization...'); print('Requesting tracking authorization...');

View File

@ -64,6 +64,74 @@ class VehicleTest {
} }
}, },
); );
patrol(
'License',
(PatrolIntegrationTester tester) async {
$ = tester;
$.tester.printToConsole('Vehicle Page');
await _loggedWithMultiLocalsAccount($);
// await StorageHelper().set(
// LicenseKeys.vehiclesManager.value,
// <String, dynamic>{
// 'display': 'VISIVEL',
// 'expirationDate': '',
// 'startDate': '',
// 'quantity': 0,
// },
// );
// // await $.pumpAndSettle();
// ff.navigatorKey.currentContext!.go('/vehiclesOnThePropertyPage');
// await Future.delayed(const Duration(milliseconds: 1000));
await StorageHelper().set(
LicenseKeys.vehiclesManager.value,
<String, dynamic>{
'display': 'VISIVEL',
'expirationDate': '',
'startDate': '',
'quantity': 0,
},
);
await $.pumpWidgetAndSettle(const App());
ff.navigatorKey.currentContext!.go('/vehiclesOnThePropertyPage');
final String title = MenuEntry.entries //
.where((entry) => entry.key == 'FRE-HUB-VEHICLES') //
.map((entry) => entry.name)
.first;
final PatrolFinder appBar = await $(AppBar) //
.waitUntilExists();
final PatrolFinder titleAppBar = await appBar //
.$(title)
.waitUntilVisible();
expect(titleAppBar, findsOneWidget);
final PatrolFinder tab1 = await $(#TabView_Tab1) //
.waitUntilExists();
final PatrolFinder tab2 = await $(#TabView_Tab2) //
.waitUntilExists();
await tab2.tap();
await Future.delayed(const Duration(milliseconds: 500));
await tab1.tap();
final PatrolFinder listViewFinder = await $(VehicleHistoryScreen) //
.$(ListView)
.waitUntilVisible();
expect(listViewFinder, findsOneWidget);
final PatrolFinder entriesFinder =
await $(listViewFinder).$(CardItemTemplateComponentWidget).waitUntilVisible();
expect(entriesFinder, findsWidgets);
await $.pumpAndSettle();
await Future.delayed(const Duration(milliseconds: 1000));
},
);
} }
static Future<void> historyScreen() async { static Future<void> historyScreen() async {

View File

@ -19,12 +19,10 @@ class BottomArrowLinkedLocalsComponentWidget extends StatefulWidget {
ApiCallResponse? response; ApiCallResponse? response;
@override @override
State<BottomArrowLinkedLocalsComponentWidget> createState() => State<BottomArrowLinkedLocalsComponentWidget> createState() => _BottomArrowLinkedLocalsComponentWidgetState();
_BottomArrowLinkedLocalsComponentWidgetState();
} }
class _BottomArrowLinkedLocalsComponentWidgetState class _BottomArrowLinkedLocalsComponentWidgetState extends State<BottomArrowLinkedLocalsComponentWidget> {
extends State<BottomArrowLinkedLocalsComponentWidget> {
late BottomArrowLinkedLocalsComponentModel _model; late BottomArrowLinkedLocalsComponentModel _model;
bool _loading = false; bool _loading = false;
@ -42,8 +40,7 @@ class _BottomArrowLinkedLocalsComponentWidgetState
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_model = _model = createModel(context, () => BottomArrowLinkedLocalsComponentModel());
createModel(context, () => BottomArrowLinkedLocalsComponentModel());
_localsFuture = _fetchLocals(); _localsFuture = _fetchLocals();
} }
@ -109,14 +106,10 @@ class _BottomArrowLinkedLocalsComponentWidgetState
if (isEnabled) { if (isEnabled) {
final local = locals[0]; final local = locals[0];
await StorageHelper() await StorageHelper().set(ProfileStorageKey.clientName.key, local['CLI_NOME']);
.set(ProfileStorageKey.clientName.key, local['CLI_NOME']); await StorageHelper().set(ProfileStorageKey.ownerName.key, local['CLU_OWNER_DSC']);
await StorageHelper() await StorageHelper().set(ProfileStorageKey.clientUUID.key, local['CLI_ID']);
.set(ProfileStorageKey.ownerName.key, local['CLU_OWNER_DSC']); await StorageHelper().set(ProfileStorageKey.ownerUUID.key, local['CLU_OWNER_ID']);
await StorageHelper()
.set(ProfileStorageKey.clientUUID.key, local['CLI_ID']);
await StorageHelper()
.set(ProfileStorageKey.ownerUUID.key, local['CLU_OWNER_ID']);
context.pop(); context.pop();
return widget.response; return widget.response;
@ -140,22 +133,20 @@ class _BottomArrowLinkedLocalsComponentWidgetState
return null; return null;
} }
static Future<void> _handleError( static Future<void> _handleError(BuildContext context, String errorMsg) async {
BuildContext context, String errorMsg) async {
await DialogUtil.error(context, errorMsg); await DialogUtil.error(context, errorMsg);
} }
Future<dynamic> _fetchResponseLink(String status, String cliID) async { Future<dynamic> _fetchResponseLink(String status, String cliID) async {
try { try {
await StorageHelper().set(ProfileStorageKey.clientUUID.key, cliID); await StorageHelper().set(ProfileStorageKey.clientUUID.key, cliID);
var response = await PhpGroup.resopndeVinculo.call(tarefa: status); var response = await PhpGroup.respondeVinculo.call(tarefa: status);
if (response.jsonBody['error'] == false) { if (response.jsonBody['error'] == false) {
return { return {
'error': false, 'error': false,
'error_msg': FFLocalizations.of(context).getVariableText( 'error_msg': FFLocalizations.of(context)
ptText: "Vínculo Ativado com Sucesso", .getVariableText(ptText: "Vínculo Ativado com Sucesso", enText: "Link Activated Successfully")
enText: "Link Activated Successfully")
}; };
} else { } else {
await StorageHelper().set(ProfileStorageKey.clientUUID.key, ''); await StorageHelper().set(ProfileStorageKey.clientUUID.key, '');
@ -163,8 +154,7 @@ class _BottomArrowLinkedLocalsComponentWidgetState
} }
} catch (e, s) { } catch (e, s) {
await DialogUtil.errorDefault(context); await DialogUtil.errorDefault(context);
LogUtil.requestAPIFailed( LogUtil.requestAPIFailed('responderVinculo.php', '', 'Responder Vínculo', e, s);
'responderVinculo.php', '', 'Responder Vínculo', e, s);
return { return {
'error': true, 'error': true,
'error_msg': FFLocalizations.of(context).getVariableText( 'error_msg': FFLocalizations.of(context).getVariableText(
@ -189,17 +179,14 @@ class _BottomArrowLinkedLocalsComponentWidgetState
Map<String, Color> _statusHashMap(dynamic local) { Map<String, Color> _statusHashMap(dynamic local) {
return Map<String, Color>.from({ return Map<String, Color>.from({
if (local['CLU_STATUS'] == 'A') if (local['CLU_STATUS'] == 'A')
FFLocalizations.of(context).getVariableText( FFLocalizations.of(context).getVariableText(ptText: 'Ativo', enText: 'Active'):
ptText: 'Ativo', FlutterFlowTheme.of(context).success
enText: 'Active'): FlutterFlowTheme.of(context).success
else if (local['CLU_STATUS'] == 'B') else if (local['CLU_STATUS'] == 'B')
FFLocalizations.of(context).getVariableText( FFLocalizations.of(context).getVariableText(ptText: 'Bloqueado', enText: 'Blocked'):
ptText: 'Bloqueado', FlutterFlowTheme.of(context).error
enText: 'Blocked'): FlutterFlowTheme.of(context).error
else else
FFLocalizations.of(context).getVariableText( FFLocalizations.of(context).getVariableText(ptText: 'Pendente', enText: 'Pending'):
ptText: 'Pendente', FlutterFlowTheme.of(context).warning
enText: 'Pending'): FlutterFlowTheme.of(context).warning
}); });
} }
@ -212,21 +199,16 @@ class _BottomArrowLinkedLocalsComponentWidgetState
statusHashMap: [_statusHashMap(local)], statusHashMap: [_statusHashMap(local)],
onTapCardItemAction: () async { onTapCardItemAction: () async {
if (local['CLU_STATUS'] == 'A') { if (local['CLU_STATUS'] == 'A') {
await StorageHelper() await StorageHelper().set(ProfileStorageKey.clientUUID.key, local['CLI_ID']);
.set(ProfileStorageKey.clientUUID.key, local['CLI_ID']); await StorageHelper().set(ProfileStorageKey.clientName.key, local['CLI_NOME']);
await StorageHelper() await StorageHelper().set(ProfileStorageKey.ownerName.key, local['CLU_OWNER_DSC']);
.set(ProfileStorageKey.clientName.key, local['CLI_NOME']); await StorageHelper().set(ProfileStorageKey.ownerUUID.key, local['CLU_OWNER_ID']);
await StorageHelper()
.set(ProfileStorageKey.ownerName.key, local['CLU_OWNER_DSC']);
await StorageHelper()
.set(ProfileStorageKey.ownerUUID.key, local['CLU_OWNER_ID']);
context.pop(true); context.pop(true);
return true; return true;
} else if (local['CLU_STATUS'] == 'B') { } else if (local['CLU_STATUS'] == 'B') {
String message = FFLocalizations.of(context).getVariableText( String message = FFLocalizations.of(context).getVariableText(
ptText: ptText: 'Local Bloqueado para Acesso, Entre em Contato com Administração',
'Local Bloqueado para Acesso, Entre em Contato com Administração',
enText: 'Location Blocked for Access, Contact Administration', enText: 'Location Blocked for Access, Contact Administration',
); );
@ -242,8 +224,7 @@ class _BottomArrowLinkedLocalsComponentWidgetState
String localName = local['CLI_NOME']; String localName = local['CLI_NOME'];
showAlertDialog( showAlertDialog(
context, context,
FFLocalizations.of(context).getVariableText( FFLocalizations.of(context).getVariableText(ptText: 'Ativar Vínculo', enText: 'Activate Link'),
ptText: 'Ativar Vínculo', enText: 'Activate Link'),
FFLocalizations.of(context).getVariableText( FFLocalizations.of(context).getVariableText(
ptText: 'Deseja aceitar o vínculo a $localName?', ptText: 'Deseja aceitar o vínculo a $localName?',
enText: 'Do you wish to accept the link to $localName?'), enText: 'Do you wish to accept the link to $localName?'),
@ -300,8 +281,7 @@ class _BottomArrowLinkedLocalsComponentWidgetState
height: height - (height * 0.5), height: height - (height * 0.5),
decoration: BoxDecoration( decoration: BoxDecoration(
color: FlutterFlowTheme.of(context).primaryBackground, color: FlutterFlowTheme.of(context).primaryBackground,
borderRadius: const BorderRadius.only( borderRadius: const BorderRadius.only(topLeft: Radius.circular(25), topRight: Radius.circular(25))),
topLeft: Radius.circular(25), topRight: Radius.circular(25))),
child: Column( child: Column(
mainAxisSize: MainAxisSize.max, mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
@ -313,16 +293,13 @@ class _BottomArrowLinkedLocalsComponentWidgetState
mainAxisSize: MainAxisSize.max, mainAxisSize: MainAxisSize.max,
children: [ children: [
Center( Center(
child: Text(FFLocalizations.of(context).getVariableText( child: Text(FFLocalizations.of(context)
ptText: "Nenhum Local Encontrado.", .getVariableText(ptText: "Nenhum Local Encontrado.", enText: "No local found")),
enText: "No local found")),
) )
], ],
), ),
) )
else if (_hasData == true && else if (_hasData == true && _loading == false && _localsWrap.isNotEmpty)
_loading == false &&
_localsWrap.isNotEmpty)
Expanded(child: _listItems(context)), Expanded(child: _listItems(context)),
if (_loading == true) if (_loading == true)
Container( Container(
@ -339,8 +316,7 @@ class _BottomArrowLinkedLocalsComponentWidgetState
padding: const EdgeInsets.only(top: 10), padding: const EdgeInsets.only(top: 10),
child: Center( child: Center(
child: Text( child: Text(
FFLocalizations.of(context).getVariableText( FFLocalizations.of(context).getVariableText(ptText: 'Escolha um local', enText: 'Choose a location'),
ptText: 'Escolha um local', enText: 'Choose a location'),
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
style: const TextStyle(fontWeight: FontWeight.bold), style: const TextStyle(fontWeight: FontWeight.bold),
)))), )))),

View File

@ -47,7 +47,7 @@ class PhpGroup extends Api {
static GetMessagesCall getMessagesCall = GetMessagesCall(); static GetMessagesCall getMessagesCall = GetMessagesCall();
static ChangeNotifica changeNotifica = ChangeNotifica(); static ChangeNotifica changeNotifica = ChangeNotifica();
static UpdateIDE updateIDE = UpdateIDE(); static UpdateIDE updateIDE = UpdateIDE();
static RespondeVinculo resopndeVinculo = RespondeVinculo(); static RespondeVinculo respondeVinculo = RespondeVinculo();
static ChangePass changePass = ChangePass(); static ChangePass changePass = ChangePass();
static ChangePanic changePanic = ChangePanic(); static ChangePanic changePanic = ChangePanic();
static DeleteAccount deleteAccount = DeleteAccount(); static DeleteAccount deleteAccount = DeleteAccount();

View File

@ -224,7 +224,7 @@ class LocalsRemoteDataSourceImpl implements LocalsRemoteDataSource {
enText: 'Device unlinked successfully', enText: 'Device unlinked successfully',
ptText: 'Dispositivo desvinculado com sucesso', ptText: 'Dispositivo desvinculado com sucesso',
); );
final bool status = await PhpGroup.resopndeVinculo.call(tarefa: 'I').then((value) async { final bool status = await PhpGroup.respondeVinculo.call(tarefa: 'I').then((value) async {
if (value.jsonBody['error'] == false) { if (value.jsonBody['error'] == false) {
await StorageHelper().set(ProfileStorageKey.clientName.key, ''); await StorageHelper().set(ProfileStorageKey.clientName.key, '');
await StorageHelper().set(ProfileStorageKey.ownerName.key, ''); await StorageHelper().set(ProfileStorageKey.ownerName.key, '');

View File

@ -11,13 +11,10 @@ import 'package:hub/shared/utils/log_util.dart';
class LocalUtil { class LocalUtil {
static void handleError(BuildContext context, String errorMsg) async { static void handleError(BuildContext context, String errorMsg) async {
final String devUUID = final String devUUID = await StorageHelper().get(ProfileStorageKey.devUUID.key) ?? '';
await StorageHelper().get(ProfileStorageKey.devUUID.key) ?? ''; final String userUUID = await StorageHelper().get(ProfileStorageKey.userUUID.key) ?? '';
final String userUUID =
await StorageHelper().get(ProfileStorageKey.userUUID.key) ?? '';
final bool isAuthenticated = userUUID.isNotEmpty && devUUID.isNotEmpty; final bool isAuthenticated = userUUID.isNotEmpty && devUUID.isNotEmpty;
final bool isDevLinked = final bool isDevLinked = !errorMsg.contains('Esse dispositivo nao pertence a esse usuario');
!errorMsg.contains('Esse dispositivo nao pertence a esse usuario');
log('() => isLinked: $errorMsg'); log('() => isLinked: $errorMsg');
if (!isAuthenticated) { if (!isAuthenticated) {
errorMsg = FFLocalizations.of(context).getVariableText( errorMsg = FFLocalizations.of(context).getVariableText(
@ -39,20 +36,15 @@ class LocalUtil {
// await DialogUtil.error(context, errorMsg).whenComplete(() async => await LocalsRemoteDataSourceImpl().selectLocal(context, null)); // await DialogUtil.error(context, errorMsg).whenComplete(() async => await LocalsRemoteDataSourceImpl().selectLocal(context, null));
} }
static Future<bool> handleUnavailable( static Future<bool> handleUnavailable(BuildContext context, List<dynamic> locals) async {
BuildContext context, List<dynamic> locals) async {
log('() => isUnavailable'); log('() => isUnavailable');
try { try {
await StorageHelper() await StorageHelper().set(ProfileStorageKey.clientUUID.key, locals[0]['CLI_ID']);
.set(ProfileStorageKey.clientUUID.key, locals[0]['CLI_ID']); await StorageHelper().set(ProfileStorageKey.ownerUUID.key, locals[0]['CLU_OWNER_ID']);
await StorageHelper() await StorageHelper().set(ProfileStorageKey.clientName.key, locals[0]['CLI_NOME']);
.set(ProfileStorageKey.ownerUUID.key, locals[0]['CLU_OWNER_ID']); await StorageHelper().set(ProfileStorageKey.ownerName.key, locals[0]['CLU_OWNER_DSC']);
await StorageHelper()
.set(ProfileStorageKey.clientName.key, locals[0]['CLI_NOME']);
await StorageHelper()
.set(ProfileStorageKey.ownerName.key, locals[0]['CLU_OWNER_DSC']);
var response = await PhpGroup.resopndeVinculo.call(tarefa: 'A'); var response = await PhpGroup.respondeVinculo.call(tarefa: 'A');
if (response.jsonBody['error'] == true) { if (response.jsonBody['error'] == true) {
await StorageHelper().set(ProfileStorageKey.clientUUID.key, ''); await StorageHelper().set(ProfileStorageKey.clientUUID.key, '');
await StorageHelper().set(ProfileStorageKey.ownerUUID.key, ''); await StorageHelper().set(ProfileStorageKey.ownerUUID.key, '');
@ -62,13 +54,10 @@ class LocalUtil {
return false; return false;
} }
if (response.jsonBody['error'] == false) if (response.jsonBody['error'] == false)
return await LocalsRemoteDataSourceImpl() return await LocalsRemoteDataSourceImpl().processProperty(context).then((value) => value);
.processProperty(context)
.then((value) => value);
} catch (e, s) { } catch (e, s) {
await DialogUtil.errorDefault(context); await DialogUtil.errorDefault(context);
LogUtil.requestAPIFailed( LogUtil.requestAPIFailed('responderVinculo.php', '', 'Responder Vínculo', e, s);
'responderVinculo.php', '', 'Responder Vínculo', e, s);
return false; return false;
} }
return false; return false;
@ -76,19 +65,12 @@ class LocalUtil {
static Future<bool> handleEnabled(BuildContext context, dynamic local) async { static Future<bool> handleEnabled(BuildContext context, dynamic local) async {
log('() => isEnabled'); log('() => isEnabled');
await StorageHelper() await StorageHelper().set(ProfileStorageKey.clientUUID.key, local['CLI_ID']);
.set(ProfileStorageKey.clientUUID.key, local['CLI_ID']); await StorageHelper().set(ProfileStorageKey.ownerUUID.key, local['CLU_OWNER_ID']);
await StorageHelper() await StorageHelper().set(ProfileStorageKey.clientName.key, local['CLI_NOME']);
.set(ProfileStorageKey.ownerUUID.key, local['CLU_OWNER_ID']); await StorageHelper().set(ProfileStorageKey.ownerName.key, local['CLU_OWNER_DSC']);
await StorageHelper() await StorageHelper().set(ProfileStorageKey.userName.key, local['USU_NOME']);
.set(ProfileStorageKey.clientName.key, local['CLI_NOME']); return await LocalsRemoteDataSourceImpl().processProperty(context).then((v) async {
await StorageHelper()
.set(ProfileStorageKey.ownerName.key, local['CLU_OWNER_DSC']);
await StorageHelper()
.set(ProfileStorageKey.userName.key, local['USU_NOME']);
return await LocalsRemoteDataSourceImpl()
.processProperty(context)
.then((v) async {
if (v == true) return await LicenseRepositoryImpl().updateLicense(); if (v == true) return await LicenseRepositoryImpl().updateLicense();
return v; return v;
}); });
@ -111,10 +93,8 @@ class LocalUtil {
static Future<bool> updateStorageUtil(Map<String, dynamic> jsonBody) async { static Future<bool> updateStorageUtil(Map<String, dynamic> jsonBody) async {
try { try {
await StorageHelper() await StorageHelper().set(LocalsStorageKey.whatsapp.key, jsonBody['whatsapp'] ?? false);
.set(LocalsStorageKey.whatsapp.key, jsonBody['whatsapp'] ?? false); await StorageHelper().set(LocalsStorageKey.provisional.key, jsonBody['provisional'] ?? false);
await StorageHelper().set(
LocalsStorageKey.provisional.key, jsonBody['provisional'] ?? false);
await StorageHelper().set( await StorageHelper().set(
LocalsStorageKey.pets.key, LocalsStorageKey.pets.key,
jsonBody['pet'] ?? false, jsonBody['pet'] ?? false,
@ -136,21 +116,14 @@ class LocalUtil {
); );
} }
await StorageHelper().set( await StorageHelper().set(LocalsStorageKey.petAmount.key,
LocalsStorageKey.petAmount.key, jsonBody['petAmountRegister']?.toString().isEmpty ?? true ? '0' : jsonBody['petAmountRegister'].toString());
jsonBody['petAmountRegister']?.toString().isEmpty ?? true await StorageHelper().set(ProfileStorageKey.userName.key, jsonBody['visitado']['VDO_NOME'] ?? '');
? '0' await StorageHelper().set(ProfileStorageKey.userEmail.key, jsonBody['visitado']['VDO_EMAIL'] ?? '');
: jsonBody['petAmountRegister'].toString()); await StorageHelper().set(LocalsStorageKey.provisional.key, jsonBody['provisional'] ?? false);
await StorageHelper().set(ProfileStorageKey.userName.key,
jsonBody['visitado']['VDO_NOME'] ?? '');
await StorageHelper().set(ProfileStorageKey.userEmail.key,
jsonBody['visitado']['VDO_EMAIL'] ?? '');
await StorageHelper().set(
LocalsStorageKey.provisional.key, jsonBody['provisional'] ?? false);
final bool isNewVersion = jsonBody['newVersion'] ?? false; final bool isNewVersion = jsonBody['newVersion'] ?? false;
await StorageHelper() await StorageHelper().set(LocalsStorageKey.isNewVersion.key, isNewVersion);
.set(LocalsStorageKey.isNewVersion.key, isNewVersion);
return isNewVersion; return isNewVersion;
} catch (e, s) { } catch (e, s) {
log('Error in _updateStorageUtil: $e', stackTrace: s); log('Error in _updateStorageUtil: $e', stackTrace: s);
@ -163,44 +136,30 @@ class LocalUtil {
} }
static Future<bool> isInactived(List<dynamic> locals) async { static Future<bool> isInactived(List<dynamic> locals) async {
String cliUUID = String cliUUID = (await StorageHelper().get(ProfileStorageKey.clientUUID.key)) ?? '';
(await StorageHelper().get(ProfileStorageKey.clientUUID.key)) ?? ''; return locals.where((local) => local['CLI_ID'] != cliUUID && local['CLU_STATUS'] == 'A').isNotEmpty;
return locals
.where(
(local) => local['CLI_ID'] != cliUUID && local['CLU_STATUS'] == 'A')
.isNotEmpty;
} }
static bool isPending(List<dynamic> locals) { static bool isPending(List<dynamic> locals) {
return locals return locals.where((local) => local['CLU_STATUS'] != 'B' && local['CLU_STATUS'] != 'A').isNotEmpty;
.where(
(local) => local['CLU_STATUS'] != 'B' && local['CLU_STATUS'] != 'A')
.isNotEmpty;
} }
static Future<bool> isUnselected() async { static Future<bool> isUnselected() async {
String cliUUID = String cliUUID = (await StorageHelper().get(ProfileStorageKey.clientUUID.key)) ?? '';
(await StorageHelper().get(ProfileStorageKey.clientUUID.key)) ?? ''; String cliName = (await StorageHelper().get(ProfileStorageKey.clientName.key)) ?? '';
String cliName = String ownerUUID = (await StorageHelper().get(ProfileStorageKey.ownerUUID.key)) ?? '';
(await StorageHelper().get(ProfileStorageKey.clientName.key)) ?? '';
String ownerUUID =
(await StorageHelper().get(ProfileStorageKey.ownerUUID.key)) ?? '';
return cliUUID.isEmpty && cliName.isEmpty && ownerUUID.isEmpty; return cliUUID.isEmpty && cliName.isEmpty && ownerUUID.isEmpty;
} }
static Future<bool> isSelected(bool isInactived) async { static Future<bool> isSelected(bool isInactived) async {
String cliUUID = String cliUUID = (await StorageHelper().get(ProfileStorageKey.clientUUID.key)) ?? '';
(await StorageHelper().get(ProfileStorageKey.clientUUID.key)) ?? ''; String cliName = (await StorageHelper().get(ProfileStorageKey.clientName.key)) ?? '';
String cliName =
(await StorageHelper().get(ProfileStorageKey.clientName.key)) ?? '';
return cliUUID.isNotEmpty && cliName.isNotEmpty && isInactived; return cliUUID.isNotEmpty && cliName.isNotEmpty && isInactived;
} }
static Future<bool> isAvailable() async { static Future<bool> isAvailable() async {
String cliUUID = String cliUUID = (await StorageHelper().get(ProfileStorageKey.clientUUID.key)) ?? '';
(await StorageHelper().get(ProfileStorageKey.clientUUID.key)) ?? ''; String cliName = (await StorageHelper().get(ProfileStorageKey.clientName.key)) ?? '';
String cliName =
(await StorageHelper().get(ProfileStorageKey.clientName.key)) ?? '';
return cliUUID.isNotEmpty && cliName.isNotEmpty; return cliUUID.isNotEmpty && cliName.isNotEmpty;
} }
} }

View File

@ -9,23 +9,16 @@ import 'package:hub/shared/extensions/dialog_extensions.dart';
import 'package:hub/shared/utils/path_util.dart'; import 'package:hub/shared/utils/path_util.dart';
abstract class MenuLocalDataSource { abstract class MenuLocalDataSource {
Future<MenuItem?> addMenuEntry(Key key, EnumMenuItem item, Future<MenuItem?> addMenuEntry(
List<MenuItem?> entries, IconData icon, String text, Function() action); Key key, EnumMenuItem item, List<MenuItem?> entries, IconData icon, String text, Function() action);
Future<bool> processDisplayDefault( Future<bool> processDisplayDefault(EnumMenuItem item, MenuEntry opt, List<MenuItem?> entries);
EnumMenuItem item, MenuEntry opt, List<MenuItem?> entries);
Future<void> handleMenu(EnumMenuItem item, EnumDisplay display, MenuEntry opt, Future<void> handleMenu(EnumMenuItem item, EnumDisplay display, MenuEntry opt, List<MenuItem?> entries);
List<MenuItem?> entries);
Future<bool> processStartDate(String startDate, MenuEntry entry);
Future<bool> processExpirationDate(String expirationDate, MenuEntry entry);
} }
class MenuLocalDataSourceImpl implements MenuLocalDataSource { class MenuLocalDataSourceImpl implements MenuLocalDataSource {
static final MenuLocalDataSourceImpl _instance = static final MenuLocalDataSourceImpl _instance = MenuLocalDataSourceImpl._internal();
MenuLocalDataSourceImpl._internal();
factory MenuLocalDataSourceImpl() => _instance; factory MenuLocalDataSourceImpl() => _instance;
@ -52,12 +45,9 @@ class MenuLocalDataSourceImpl implements MenuLocalDataSource {
} }
@override @override
Future<bool> processDisplayDefault( Future<bool> processDisplayDefault(EnumMenuItem item, MenuEntry opt, List<MenuItem?> entries) async {
EnumMenuItem item, MenuEntry opt, List<MenuItem?> entries) async {
if (opt.key == 'FRE-HUB-LOGOUT') { if (opt.key == 'FRE-HUB-LOGOUT') {
await addMenuEntry( await addMenuEntry(ValueKey<String>(opt.key), item, entries, opt.icon, opt.name, () async {
ValueKey<String>(opt.key), item, entries, opt.icon, opt.name,
() async {
await AuthenticationService.signOut(navigatorKey.currentContext!); await AuthenticationService.signOut(navigatorKey.currentContext!);
}); });
return true; return true;
@ -66,23 +56,17 @@ class MenuLocalDataSourceImpl implements MenuLocalDataSource {
} }
@override @override
Future<void> handleMenu(EnumMenuItem item, EnumDisplay display, MenuEntry opt, Future<void> handleMenu(EnumMenuItem item, EnumDisplay display, MenuEntry opt, List<MenuItem?> entries) async {
List<MenuItem?> entries) async {
try { try {
switch (display.value) { switch (display.value) {
case 'VISIVEL': case 'VISIVEL':
await addMenuEntry( await addMenuEntry(ValueKey<String>(opt.key), item, entries, opt.icon, opt.name, () async {
ValueKey<String>(opt.key), item, entries, opt.icon, opt.name,
() async {
await PathUtil.nav(opt.route); await PathUtil.nav(opt.route);
}); });
break; break;
case 'DESABILITADO': case 'DESABILITADO':
await addMenuEntry( await addMenuEntry(ValueKey<String>(opt.key), item, entries, opt.icon, opt.name, () async {
ValueKey<String>(opt.key), item, entries, opt.icon, opt.name, await DialogUnavailable.unavailableFeature(navigatorKey.currentContext!);
() async {
await DialogUnavailable.unavailableFeature(
navigatorKey.currentContext!);
}); });
break; break;
case 'INVISIVEL': case 'INVISIVEL':
@ -92,30 +76,4 @@ class MenuLocalDataSourceImpl implements MenuLocalDataSource {
log('Error processing display for module ${opt.key}: $e'); log('Error processing display for module ${opt.key}: $e');
} }
} }
@override
Future<bool> processStartDate(String startDate, MenuEntry opt) async {
try {
if (startDate.isEmpty) return true;
final start = DateTime.tryParse(startDate);
if (start == null) return false;
return DateTime.now().isAfter(start);
} catch (e) {
log('Error processing start date for module ${opt.key}: $e');
}
return false;
}
@override
Future<bool> processExpirationDate(
String expirationDate, MenuEntry opt) async {
try {
if (expirationDate.isEmpty) return false;
final expiration = DateTime.tryParse(expirationDate);
return expiration != null && DateTime.now().isAfter(expiration);
} catch (e) {
log('Error processing expiration date for module ${opt.key}: $e');
}
return false;
}
} }

View File

@ -4,20 +4,19 @@ import 'package:hub/features/menu/index.dart';
import 'package:hub/features/module/index.dart'; import 'package:hub/features/module/index.dart';
import 'package:hub/features/storage/index.dart'; import 'package:hub/features/storage/index.dart';
import 'package:hub/flutter_flow/custom_functions.dart'; import 'package:hub/flutter_flow/custom_functions.dart';
import 'package:hub/shared/utils/datetime_util.dart';
class MenuRepositoryImpl implements MenuRepository { class MenuRepositoryImpl implements MenuRepository {
final MenuLocalDataSource menuDataSource = MenuLocalDataSourceImpl(); final MenuLocalDataSource menuDataSource = MenuLocalDataSourceImpl();
@override @override
Future<List<MenuItem?>> entries2Items( Future<List<MenuItem?>> entries2Items(List<MenuEntry> menuEntries, EnumMenuItem menuItem) async {
List<MenuEntry> menuEntries, EnumMenuItem menuItem) async {
List<MenuItem?> entries = []; List<MenuItem?> entries = [];
// final bool isNewVersion = await StorageHelper().get(KeychainStorageKey.isNewVersion.value).then((v) => v.toBoolean()); // final bool isNewVersion = await StorageHelper().get(KeychainStorageKey.isNewVersion.value).then((v) => v.toBoolean());
try { try {
for (var entry in menuEntries) { for (var entry in menuEntries) {
final bool isDefault = await menuDataSource.processDisplayDefault( final bool isDefault = await menuDataSource.processDisplayDefault(menuItem, entry, entries);
menuItem, entry, entries);
if (isDefault) continue; if (isDefault) continue;
final licenseValue = await LicenseRepositoryImpl().getModule(entry.key); final licenseValue = await LicenseRepositoryImpl().getModule(entry.key);
if (licenseValue != null) { if (licenseValue != null) {
@ -25,22 +24,18 @@ class MenuRepositoryImpl implements MenuRepository {
final display = EnumDisplay.fromString(licenseMap['display']); final display = EnumDisplay.fromString(licenseMap['display']);
final startDate = licenseMap['startDate'] ?? ''; final startDate = licenseMap['startDate'] ?? '';
final expirationDate = licenseMap['expirationDate'] ?? ''; final expirationDate = licenseMap['expirationDate'] ?? '';
final isStarted = final isStarted = await DateTimeUtil.processStartDate(startDate);
await menuDataSource.processStartDate(startDate, entry); final isExpired = await DateTimeUtil.processExpirationDate(expirationDate);
final isExpired =
await menuDataSource.processExpirationDate(expirationDate, entry);
if (isStarted && !isExpired) { if (isStarted && !isExpired) {
await menuDataSource.handleMenu(menuItem, display, entry, entries); await menuDataSource.handleMenu(menuItem, display, entry, entries);
} }
if (isExpired) { if (isExpired) {
log('Entry ${entry.key} is expired'); log('Entry ${entry.key} is expired');
await menuDataSource.handleMenu( await menuDataSource.handleMenu(menuItem, EnumDisplay.inactive, entry, entries);
menuItem, EnumDisplay.inactive, entry, entries);
} }
if (!isStarted) { if (!isStarted) {
log('Entry ${entry.key} is not started'); log('Entry ${entry.key} is not started');
await menuDataSource.handleMenu( await menuDataSource.handleMenu(menuItem, EnumDisplay.inactive, entry, entries);
menuItem, EnumDisplay.inactive, entry, entries);
} }
} }
} }
@ -50,11 +45,9 @@ class MenuRepositoryImpl implements MenuRepository {
return entries; return entries;
} }
Future<EnumDisplay> processDisplay( Future<EnumDisplay> processDisplay(Map<String, dynamic> module, bool isNewVersion) async {
Map<String, dynamic> module, bool isNewVersion) async {
if (await _shouldUpdateDisplay(module, isNewVersion)) { if (await _shouldUpdateDisplay(module, isNewVersion)) {
final displayValue = final displayValue = module['display'] == EnumDisplay.active ? 'VISIVEL' : 'INVISIVEL';
module['display'] == EnumDisplay.active ? 'VISIVEL' : 'INVISIVEL';
await LicenseLocalDataSourceImpl(DatabaseService.database) await LicenseLocalDataSourceImpl(DatabaseService.database)
.setDisplayByKey(['FRE-HUB-ABOUT-PROPERTY'], displayValue); .setDisplayByKey(['FRE-HUB-ABOUT-PROPERTY'], displayValue);
return EnumDisplay.fromString(displayValue); return EnumDisplay.fromString(displayValue);
@ -63,13 +56,8 @@ class MenuRepositoryImpl implements MenuRepository {
return EnumDisplay.fromString(module['display']); return EnumDisplay.fromString(module['display']);
} }
Future<bool> _shouldUpdateDisplay( Future<bool> _shouldUpdateDisplay(Map<String, dynamic> module, bool isNewVersion) async {
Map<String, dynamic> module, bool isNewVersion) async { const keysToCheck = [LicenseKeys.residents, LicenseKeys.vehicles, LicenseKeys.openedVisits];
const keysToCheck = [
LicenseKeys.residents,
LicenseKeys.vehicles,
LicenseKeys.openedVisits
];
return isNewVersion && keysToCheck.any((key) => module['key'] == key.value); return isNewVersion && keysToCheck.any((key) => module['key'] == key.value);
} }
} }

View File

@ -5,7 +5,15 @@ import 'package:hub/flutter_flow/index.dart';
import 'package:hub/pages/vehicles_on_the_property/vehicles_on_the_property.dart'; import 'package:hub/pages/vehicles_on_the_property/vehicles_on_the_property.dart';
import 'package:hub/shared/utils/index.dart'; import 'package:hub/shared/utils/index.dart';
class VehicleModel extends FlutterFlowModel<VehiclePage> { /// [VehicleModel] is a class that contains the business logic of the vehicle page.
class VehicleModel extends FlutterFlowModel<VehiclePage>
with _BaseVehiclePage, _VehicleHistoryScreenModel, _VehicleRegisterScreenModel, _VehicleUpdateScreenModel {
/// [VehicleModel] is a singleton class that contains the business logic of the vehicle page.
static VehicleModel? _instance = VehicleModel._internal();
VehicleModel._internal();
factory VehicleModel() => _instance ?? VehicleModel._internal();
static void resetInstance() => _instance = null;
@override @override
void initState(BuildContext context) { void initState(BuildContext context) {
resetInstance(); resetInstance();
@ -36,25 +44,31 @@ class VehicleModel extends FlutterFlowModel<VehiclePage> {
textFieldControllerModel!.dispose(); textFieldControllerModel!.dispose();
} }
static VehicleModel? _instance = VehicleModel._internal();
VehicleModel._internal();
factory VehicleModel() => _instance ?? VehicleModel._internal();
static void resetInstance() => _instance = null;
dynamic item;
String? vehicleId;
late final TabController tabBarController;
VoidCallback? onUpdateVehicle;
VoidCallback? onRegisterVehicle;
VoidCallback? safeSetState;
final GlobalKey<FormState> registerFormKey = GlobalKey<FormState>(); final GlobalKey<FormState> registerFormKey = GlobalKey<FormState>();
final GlobalKey<FormState> updateFormKey = GlobalKey<FormState>(); final GlobalKey<FormState> updateFormKey = GlobalKey<FormState>();
ApiCallResponse? vehicleResponse; Future<void> initAsync() async {}
bool isEditing = false;
bool isFormValid(BuildContext context) {
if (registerFormKey.currentState == null) return false;
return registerFormKey.currentState!.validate();
}
}
/// [_BaseVehiclePage] is a mixin that contains the base logic of the vehicle page.
mixin class _BaseVehiclePage {
int count = 0;
late final VehicleModel model;
late final TabController tabBarController;
dynamic item;
BuildContext context = navigatorKey.currentContext!; BuildContext context = navigatorKey.currentContext!;
bool isEditing = false;
String? vehicleId;
ApiCallResponse? vehicleResponse;
VoidCallback? onUpdateVehicle;
VoidCallback? onRegisterVehicle;
VoidCallback? safeSetState;
FocusNode? textFieldFocusLicensePlate; FocusNode? textFieldFocusLicensePlate;
TextEditingController? textFieldControllerLicensePlate; TextEditingController? textFieldControllerLicensePlate;
@ -105,8 +119,35 @@ class VehicleModel extends FlutterFlowModel<VehiclePage> {
return null; return null;
} }
Future<void> initAsync() async {} void switchTab(int index) {
tabBarController.animateTo(index);
if (index == 0) handleEditingChanged(false);
safeSetState?.call();
}
void clearFields() async {
textFieldControllerLicensePlate!.clear();
textFieldControllerColor!.clear();
textFieldControllerModel!.clear();
}
void handleEditingChanged(bool editing) {
isEditing = editing;
clearFields();
}
void setEditForm() {
if (item != null) {
vehicleId = item['vehicleId'];
textFieldControllerLicensePlate!.text = item['licensePlate'];
textFieldControllerColor!.text = item['color'];
textFieldControllerModel!.text = item['model'];
}
}
}
/// [_VehicleHistoryScreenModel] is a mixin that contains the business logic of the vehicle history page.
mixin _VehicleHistoryScreenModel on _BaseVehiclePage {
Map<String, Color>? generateStatusColorMap(dynamic uItem) { Map<String, Color>? generateStatusColorMap(dynamic uItem) {
final statusMap = { final statusMap = {
"ATI": { "ATI": {
@ -179,35 +220,20 @@ class VehicleModel extends FlutterFlowModel<VehiclePage> {
), ),
); );
return [ final updateText = FFLocalizations.of(context).getVariableText(ptText: 'Editar', enText: 'Edit');
if (item['status'].contains('AGU')) final updateIcon = Icon(Icons.edit, color: iconButtonColor);
FFButtonWidget( Future updateOnPressed() async {
text: FFLocalizations.of(context).getVariableText(
ptText: 'Editar',
enText: 'Edit',
),
icon: Icon(
Icons.close,
color: iconButtonColor,
),
onPressed: () async {
context.pop(); context.pop();
isEditing = true; isEditing = true;
item = item; item = item;
switchTab(1); switchTab(1);
setEditForm(); setEditForm();
}, }
options: buttonOptions,
), final cancelText = FFLocalizations.of(context).getVariableText(ptText: 'Cancelar', enText: 'Cancel');
if (item['status'].contains('APR') || item['status'].contains('AGU')) final cancelIcon = Icon(Icons.close, color: iconButtonColor);
FFButtonWidget( Future cancelOnPressed() async {
text: FFLocalizations.of(context).getVariableText(
ptText: 'Cancelar',
enText: 'Cancel',
),
icon: Icon(Icons.close, color: iconButtonColor),
onPressed: () async {
showAlertDialog( showAlertDialog(
context, context,
FFLocalizations.of(context).getVariableText( FFLocalizations.of(context).getVariableText(
@ -217,12 +243,113 @@ class VehicleModel extends FlutterFlowModel<VehiclePage> {
FFLocalizations.of(context).getVariableText( FFLocalizations.of(context).getVariableText(
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 { ),
() async => await processCancelRequest(item['status']),
);
}
final deleteText = FFLocalizations.of(context).getVariableText(ptText: 'Excluir', enText: 'Delete');
final deleteIcon = Icon(Icons.delete, color: iconButtonColor);
Future deleteOnPressed() async {
showAlertDialog(
context,
FFLocalizations.of(context).getVariableText(
ptText: 'Excluir Veículo',
enText: 'Delete Vehicle',
),
FFLocalizations.of(context).getVariableText(
ptText: 'Você tem certeza que deseja excluir esse veículo?',
enText: 'Are you sure you want to delete this vehicle?',
),
() async => await processDeleteRequest(),
);
}
return [
if (item['status'].contains('AGU'))
FFButtonWidget(
text: updateText,
icon: updateIcon,
onPressed: updateOnPressed,
options: buttonOptions,
),
if (item['status'].contains('APR') || item['status'].contains('AGU'))
FFButtonWidget(
text: cancelText,
icon: cancelIcon,
onPressed: cancelOnPressed,
options: buttonOptions,
),
if (item['status'].contains('ATI'))
FFButtonWidget(
text: deleteText,
icon: deleteIcon,
onPressed: deleteOnPressed,
options: buttonOptions,
),
];
}
Future<void> processDeleteRequest() async {
int id = item['vehicleId']; int id = item['vehicleId'];
await PhpGroup.deleteVehicle.call(vehicleId: id).then((value) { await PhpGroup.deleteVehicle.call(vehicleId: id).then((value) {
context.pop(value); context.pop(value);
context.pop(value); context.pop(value);
// ignore: unrelated_type_equality_checks
if (value == false) {
showSnackbar(
context,
FFLocalizations.of(context).getVariableText(
ptText: 'Erro ao excluir veículo',
enText: 'Error deleting vehicle',
),
true,
);
// ignore: unrelated_type_equality_checks
} else if (value == true) {
showSnackbar(
context,
FFLocalizations.of(context).getVariableText(
enText: 'Success deleting vehicle',
ptText: 'Succeso ao excluir veículo',
),
false,
);
}
}).catchError((err, stack) {
context.pop();
showSnackbar(
context,
FFLocalizations.of(context).getVariableText(
enText: 'Error deleting vehicle',
ptText: 'Erro ao excluir veículo',
),
true,
);
});
}
Future<void> processCancelRequest(String status) async {
late final ApiCallResponse value;
try {
switch (status) {
case 'APR_CREATE':
value = await processCancelDeleteRequest();
break;
case 'AGU_CHANGE':
value = await processCancelUpdateRequest();
break;
case 'APR_DELETE':
value = await processCancelCreateRequest();
break;
default:
break;
}
context.pop(value);
context.pop(value);
if (value.jsonBody['error'] == false) { if (value.jsonBody['error'] == false) {
showSnackbar( showSnackbar(
context, context,
@ -242,7 +369,7 @@ class VehicleModel extends FlutterFlowModel<VehiclePage> {
false, false,
); );
} }
}).catchError((err, stack) { } catch (err) {
context.pop(); context.pop();
showSnackbar( showSnackbar(
context, context,
@ -252,72 +379,22 @@ class VehicleModel extends FlutterFlowModel<VehiclePage> {
), ),
true, true,
); );
});
});
},
options: buttonOptions,
),
if (item['status'].contains('ATI'))
FFButtonWidget(
text: FFLocalizations.of(context).getVariableText(
ptText: 'Excluir',
enText: 'Delete',
),
icon: Icon(
Icons.close,
color: iconButtonColor,
),
onPressed: () async {
showAlertDialog(
context,
FFLocalizations.of(context).getVariableText(
ptText: 'Excluir Veículo',
enText: 'Delete Vehicle',
),
FFLocalizations.of(context).getVariableText(
ptText: 'Você tem certeza que deseja excluir esse veículo?',
enText: 'Are you sure you want to delete this vehicle?',
), () async {
int id = item['vehicleId'];
await PhpGroup.deleteVehicle.call(vehicleId: id).then((value) {
context.pop(value);
context.pop(value);
if (value == false) {
showSnackbar(
context,
FFLocalizations.of(context).getVariableText(
ptText: 'Erro ao excluir veículo',
enText: 'Error deleting vehicle',
),
true,
);
} else if (value == true) {
showSnackbar(
context,
FFLocalizations.of(context).getVariableText(
enText: 'Success deleting vehicle',
ptText: 'Succeso ao excluir veículo',
),
false,
);
} }
}).catchError((err, stack) { }
context.pop();
showSnackbar( Future<ApiCallResponse> processCancelDeleteRequest() async {
context, final int id = item['vehicleId'];
FFLocalizations.of(context).getVariableText( return await PhpGroup.deleteVehicle.call(vehicleId: id);
enText: 'Error deleting vehicle', }
ptText: 'Erro ao excluir veículo',
), Future<ApiCallResponse> processCancelUpdateRequest() async {
true, final int id = item['vehicleId'];
); return await PhpGroup.deleteVehicle.call(vehicleId: id);
}); }
});
}, Future<ApiCallResponse> processCancelCreateRequest() async {
options: buttonOptions, final int id = item['vehicleId'];
), return await PhpGroup.deleteVehicle.call(vehicleId: id);
];
} }
Map<String, String> generateLabelsHashMap(dynamic item) { Map<String, String> generateLabelsHashMap(dynamic item) {
@ -354,21 +431,42 @@ class VehicleModel extends FlutterFlowModel<VehiclePage> {
statusHashMap: [status], statusHashMap: [status],
); );
} }
}
void setEditForm() { /// [_VehicleRegisterScreenModel] is a mixin that contains the business logic of the vehicle register page.
if (item != null) { mixin _VehicleRegisterScreenModel on _BaseVehiclePage {
vehicleId = item['vehicleId']; Future<void> registerVehicle() async {
textFieldControllerLicensePlate!.text = item['licensePlate']; final response = await PhpGroup.registerVehicle.call(
textFieldControllerColor!.text = item['color']; licensePlate: textFieldControllerLicensePlate!.text,
textFieldControllerModel!.text = item['model']; color: textFieldControllerColor!.text,
model: textFieldControllerModel!.text,
);
if (response.jsonBody['error'] == false) {
await DialogUtil.success(
context,
FFLocalizations.of(context).getVariableText(
ptText: 'Veículo cadastrado com sucesso',
enText: 'Vehicle registered successfully',
)).then((_) async {
switchTab(0);
});
} else {
String errorMessage;
try {
errorMessage = response.jsonBody['message'];
} catch (e) {
errorMessage = FFLocalizations.of(context).getVariableText(
ptText: 'Erro ao cadastrar veículo',
enText: 'Error registering vehicle',
);
}
await DialogUtil.error(context, errorMessage);
}
} }
} }
bool isFormValid(BuildContext context) { /// [_VehicleUpdateScreenModel] is a mixin that contains the business logic of the vehicle update page.
if (registerFormKey.currentState == null) return false; mixin _VehicleUpdateScreenModel on _BaseVehiclePage {
return registerFormKey.currentState!.validate();
}
Future<void> updateVehicle() async { Future<void> updateVehicle() async {
final response = await PhpGroup.updateVehicle.call( final response = await PhpGroup.updateVehicle.call(
licensePlate: textFieldControllerLicensePlate!.text, licensePlate: textFieldControllerLicensePlate!.text,
@ -398,50 +496,4 @@ class VehicleModel extends FlutterFlowModel<VehiclePage> {
await DialogUtil.error(context, errorMessage); await DialogUtil.error(context, errorMessage);
} }
} }
Future<void> registerVehicle() async {
final response = await PhpGroup.registerVehicle.call(
licensePlate: textFieldControllerLicensePlate!.text,
color: textFieldControllerColor!.text,
model: textFieldControllerModel!.text,
);
if (response.jsonBody['error'] == false) {
await DialogUtil.success(
context,
FFLocalizations.of(context).getVariableText(
ptText: 'Veículo cadastrado com sucesso',
enText: 'Vehicle registered successfully',
)).then((_) async {
switchTab(0);
});
} else {
String errorMessage;
try {
errorMessage = response.jsonBody['message'];
} catch (e) {
errorMessage = FFLocalizations.of(context).getVariableText(
ptText: 'Erro ao cadastrar veículo',
enText: 'Error registering vehicle',
);
}
await DialogUtil.error(context, errorMessage);
}
}
void switchTab(int index) {
tabBarController.animateTo(index);
if (index == 0) handleEditingChanged(false);
safeSetState?.call();
}
void clearFields() async {
textFieldControllerLicensePlate!.clear();
textFieldControllerColor!.clear();
textFieldControllerModel!.clear();
}
void handleEditingChanged(bool editing) {
isEditing = editing;
clearFields();
}
} }

View File

@ -14,34 +14,19 @@ class VehicleRegisterScreen extends StatefulWidget {
class _VehicleRegisterScreenState extends State<VehicleRegisterScreen> { class _VehicleRegisterScreenState extends State<VehicleRegisterScreen> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
double limitedInputFontSize = LimitedFontSizeUtil.getInputFontSize(context);
double limitedHeaderFontSize = LimitedFontSizeUtil.getHeaderFontSize(context);
double limitedSubHeaderFontSize = LimitedFontSizeUtil.getSubHeaderFontSize(context);
return SingleChildScrollView( return SingleChildScrollView(
child: Column( child: Column(
mainAxisSize: MainAxisSize.max, mainAxisSize: MainAxisSize.max,
children: [ children: [
Align( _buildHeader(context),
alignment: const AlignmentDirectional(-1.0, 0.0), _buildBody(context),
child: Padding( ],
padding: const EdgeInsetsDirectional.fromSTEB(24.0, 20, 0.0, 15),
child: Text(
FFLocalizations.of(context).getVariableText(
ptText: 'Preencha o formulário de cadastro com os dados do seu veículo',
enText: 'Fill out the registration form with your vehicle data',
), ),
textAlign: TextAlign.start, );
style: FlutterFlowTheme.of(context).bodyMedium.override( }
fontFamily: FlutterFlowTheme.of(context).bodyMediumFamily,
letterSpacing: 0.0, Form _buildBody(BuildContext context) {
useGoogleFonts: GoogleFonts.asMap().containsKey(FlutterFlowTheme.of(context).bodyMediumFamily), return Form(
fontSize: limitedHeaderFontSize,
),
),
),
),
Form(
key: widget.model.registerFormKey, key: widget.model.registerFormKey,
autovalidateMode: AutovalidateMode.onUserInteraction, autovalidateMode: AutovalidateMode.onUserInteraction,
child: Column( child: Column(
@ -94,8 +79,31 @@ class _VehicleRegisterScreenState extends State<VehicleRegisterScreen> {
onPressed: widget.model.isFormValid(context) ? widget.model.registerVehicle : null), onPressed: widget.model.isFormValid(context) ? widget.model.registerVehicle : null),
), ),
], ],
)), ));
], }
Align _buildHeader(BuildContext context) {
// double limitedInputFontSize = LimitedFontSizeUtil.getInputFontSize(context);
double limitedHeaderFontSize = LimitedFontSizeUtil.getHeaderFontSize(context);
// double limitedSubHeaderFontSize = LimitedFontSizeUtil.getSubHeaderFontSize(context);
return Align(
alignment: const AlignmentDirectional(-1.0, 0.0),
child: Padding(
padding: const EdgeInsetsDirectional.fromSTEB(24.0, 20, 0.0, 15),
child: Text(
FFLocalizations.of(context).getVariableText(
ptText: 'Preencha o formulário de cadastro com os dados do seu veículo',
enText: 'Fill out the registration form with your vehicle data',
),
textAlign: TextAlign.start,
style: FlutterFlowTheme.of(context).bodyMedium.override(
fontFamily: FlutterFlowTheme.of(context).bodyMediumFamily,
letterSpacing: 0.0,
useGoogleFonts: GoogleFonts.asMap().containsKey(FlutterFlowTheme.of(context).bodyMediumFamily),
fontSize: limitedHeaderFontSize,
),
),
), ),
); );
} }

View File

@ -14,6 +14,7 @@ import 'package:hub/flutter_flow/flutter_flow_util.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/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/limited_text_size.dart'; import 'package:hub/shared/utils/limited_text_size.dart';
import 'package:hub/shared/utils/log_util.dart'; import 'package:hub/shared/utils/log_util.dart';
import 'package:material_symbols_icons/symbols.dart'; import 'package:material_symbols_icons/symbols.dart';
@ -27,6 +28,7 @@ class VehiclePage extends StatefulWidget {
const VehiclePage({super.key}); const VehiclePage({super.key});
@override @override
// ignore: library_private_types_in_public_api
_VehiclePageState createState() => _VehiclePageState(); _VehiclePageState createState() => _VehiclePageState();
} }
@ -55,24 +57,24 @@ class _VehiclePageState extends State<VehiclePage> with TickerProviderStateMixin
}; };
} }
@override // @override
void dispose() { // void dispose() {
super.dispose(); // super.dispose();
} // }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final backgroundColor = FlutterFlowTheme.of(context).primaryBackground; final backgroundColor = FlutterFlowTheme.of(context).primaryBackground;
return Scaffold( return Scaffold(
backgroundColor: backgroundColor, backgroundColor: backgroundColor,
appBar: _buildAppBar(context), appBar: _buildHeader(context),
body: buildBody(context), body: _buildBody(context),
); );
} }
/// [Body] of the page. /// [Body] of the page.
Widget buildBody(BuildContext context) { FutureBuilder<bool> _buildBody(BuildContext context) {
Widget progressEvent() { Widget progressIndicator() {
return CircularProgressIndicator( return CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>( valueColor: AlwaysStoppedAnimation<Color>(
FlutterFlowTheme.of(context).primary, FlutterFlowTheme.of(context).primary,
@ -80,22 +82,14 @@ class _VehiclePageState extends State<VehiclePage> with TickerProviderStateMixin
); );
} }
Widget errorEvent() { return FutureBuilder<bool>(
WidgetsBinding.instance.addPostFrameCallback((_) async { future: _initializeModule(),
context.pop();
await DialogUtil.errorDefault(navigatorKey.currentContext!);
});
return progressEvent();
}
return FutureBuilder<String?>(
future: LicenseRepositoryImpl().getModule('FRE-HUB-VEHICLES-MANAGER'),
builder: (context, snapshot) { builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) { if (snapshot.connectionState == ConnectionState.waiting) {
return progressEvent(); return progressIndicator();
} else if (snapshot.hasError) { } else if (snapshot.hasError) {
return errorEvent(); return progressIndicator();
} else if (snapshot.hasData && snapshot.data!.isNotEmpty) { } else if (snapshot.hasData && snapshot.data == true) {
return _buildVehicleManager(context); return _buildVehicleManager(context);
} else { } else {
return _buildVehicleHistory(context); return _buildVehicleHistory(context);
@ -104,6 +98,19 @@ class _VehiclePageState extends State<VehiclePage> with TickerProviderStateMixin
); );
} }
Future<bool> _initializeModule() async {
try {
final module = await LicenseRepositoryImpl().getModule('FRE-HUB-VEHICLES-MANAGER');
return await LicenseUtil.processModule(module);
} catch (e) {
WidgetsBinding.instance.addPostFrameCallback((_) async {
context.pop();
await DialogUtil.errorDefault(navigatorKey.currentContext!);
});
return false;
}
}
void onEditingChanged(bool value) { void onEditingChanged(bool value) {
setState(() { setState(() {
_model.handleEditingChanged(value); _model.handleEditingChanged(value);
@ -134,8 +141,8 @@ class _VehiclePageState extends State<VehiclePage> with TickerProviderStateMixin
} }
/// ----------------------------------- /// -----------------------------------
/// [AppBar] with the title of the page. /// [Header] of the page.
PreferredSizeWidget _buildAppBar(BuildContext context) { PreferredSizeWidget _buildHeader(BuildContext context) {
final theme = FlutterFlowTheme.of(context); final theme = FlutterFlowTheme.of(context);
final backgroundColor = theme.primaryBackground; final backgroundColor = theme.primaryBackground;
final primaryText = theme.primaryText; final primaryText = theme.primaryText;

View File

@ -0,0 +1,26 @@
import 'dart:developer';
class DateTimeUtil {
static Future<bool> processStartDate(String startDate) async {
try {
if (startDate.isEmpty) return true;
final start = DateTime.tryParse(startDate);
if (start == null) return false;
return DateTime.now().isAfter(start);
} catch (e) {
log('Error processing start date for module: $e');
}
return false;
}
static Future<bool> processExpirationDate(String expirationDate) async {
try {
if (expirationDate.isEmpty) return false;
final expiration = DateTime.tryParse(expirationDate);
return expiration != null && DateTime.now().isAfter(expiration);
} catch (e) {
log('Error processing expiration date for module: $e');
}
return false;
}
}

View File

@ -0,0 +1,17 @@
import 'package:hub/features/module/index.dart';
import 'package:hub/flutter_flow/index.dart';
import 'package:hub/shared/utils/datetime_util.dart';
class LicenseUtil {
static Future<bool> processModule(String? module) async {
if (module == null) return false;
final moduleMap = await stringToMap(module);
final startDate = moduleMap['startDate'] ?? '';
final expirationDate = moduleMap['expirationDate'] ?? '';
final isStarted = await DateTimeUtil.processStartDate(startDate);
final isExpired = await DateTimeUtil.processExpirationDate(expirationDate);
if (isStarted && !isExpired) return EnumDisplay.fromString(moduleMap["display"]) == EnumDisplay.active;
if (isExpired) return false;
return false;
}
}