Merge pull request #84 from FRE-Informatica/debit/fd-1038

DEBIT/FD-1038 - Escritas de Testes para o App
This commit is contained in:
Ivan Antunes 2025-01-17 14:12:44 -03:00 committed by GitHub
commit 069b46e927
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
77 changed files with 17417 additions and 272 deletions

View File

@ -1,2 +1,2 @@
gradle 8.10.2
kotlin 2.0.20
kotlin 1.8.22

View File

@ -34,7 +34,7 @@ if (keystorePropertiesFile.exists()) {
android {
namespace 'com.freaccess.hub'
compileSdkVersion 34
compileSdk 34
compileSdk 35
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
@ -53,8 +53,16 @@ android {
versionName flutterVersionName
multiDexEnabled true
consumerProguardFiles 'proguard-rules.pro'
testInstrumentationRunner "pl.leancode.patrol.PatrolJUnitRunner"
testInstrumentationRunnerArguments clearPackageData: "true"
}
testOptions {
execution "ANDROIDX_TEST_ORCHESTRATOR"
}
compileOptions {
coreLibraryDesugaringEnabled true
sourceCompatibility JavaVersion.VERSION_11
@ -73,7 +81,7 @@ android {
storePassword keystoreProperties['storePassword']
}
debug {
}
}
@ -92,6 +100,8 @@ android {
debug {
signingConfig signingConfigs.debug
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
minifyEnabled false
shrinkResources false
}
}
}
@ -106,11 +116,16 @@ dependencies {
implementation 'androidx.window:window:1.0.0'
implementation 'androidx.window:window-java:1.0.0'
implementation 'com.google.mlkit:face-detection:16.1.7'
implementation ('com.google.firebase:firebase-messaging:24.0.0') {
implementation('com.google.firebase:firebase-messaging:24.0.0') {
exclude group: 'com.google.firebase', module: 'firebase-iid'
}
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.3'
androidTestUtil "androidx.test:orchestrator:1.5.1"
// androidTestImplementation 'androidx.test:runner:1.4.0'
// androidTestImplementation 'androidx.test:rules:1.4.0'
}
apply plugin: 'com.google.gms.google-services'

View File

@ -0,0 +1,36 @@
package com.freaccess.hub;
import androidx.test.platform.app.InstrumentationRegistry;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import pl.leancode.patrol.PatrolJUnitRunner;
@RunWith(Parameterized.class)
public class MainActivityTest {
private final String dartTestName;
public MainActivityTest(String dartTestName) {
this.dartTestName = dartTestName;
}
@Parameters(name = "{0}")
public static Object[] testCases() {
PatrolJUnitRunner instrumentation = (PatrolJUnitRunner) InstrumentationRegistry.getInstrumentation();
// replace "MainActivity.class" with "io.flutter.embedding.android.FlutterActivity.class"
// if in AndroidManifest.xml in manifest/application/activity you have
// android:name="io.flutter.embedding.android.FlutterActivity"
instrumentation.setUp(MainActivity.class);
instrumentation.waitForPatrolAppService();
return instrumentation.listDartTests();
}
@Test
public void runDartTest() {
PatrolJUnitRunner instrumentation = (PatrolJUnitRunner) InstrumentationRegistry.getInstrumentation();
instrumentation.runDartTest(dartTestName);
}
}

View File

@ -1,6 +1,6 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext.kotlin_version = '2.0.20' // Replace with the latest version
ext.kotlin_version = '1.8.22'
ext.gradle_version = '8.6.0' // Replace with the latest version
ext.google_services_version = '4.4.2' // Replace with the latest version
repositories {
@ -8,12 +8,14 @@ buildscript {
mavenCentral()
}
dependencies {
classpath "com.android.tools.build:gradle:$gradle_version" // Use a versão do Gradle que corresponde à sua configuração
classpath "com.android.tools.build:gradle:$gradle_version"
// Use a versão do Gradle que corresponde à sua configuração
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "com.google.gms:google-services:$google_services_version" // Google Services plugin
}
classpath "com.google.gms:google-services:$google_services_version"
// Google Services plugin
}
}
allprojects {
repositories {
google()

View File

@ -20,7 +20,7 @@ plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id 'com.android.application' version '8.6.0' apply false
id 'com.android.library' version '8.6.0' apply false
id 'org.jetbrains.kotlin.android' version '2.0.20' apply false
id 'org.jetbrains.kotlin.android' version '1.8.22' apply false
// START: FlutterFire Configuration
@ -29,8 +29,7 @@ plugins {
// id "org.jetbrains.kotlin.android" version "1.7.10" apply false
// id "org.jetbrains.kotlin.android" version "1.8.10" apply false
}
include ":app"

15496
coverage/lcov.info Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,64 @@
import 'dart:collection';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:go_router/go_router.dart';
import 'package:hub/components/molecular_components/throw_exception/throw_exception_widget.dart';
import 'package:hub/components/organism_components/bottom_arrow_linked_locals_component/bottom_arrow_linked_locals_component_widget.dart';
import 'package:hub/components/templates_components/card_item_template_component/card_item_template_component_widget.dart';
import 'package:hub/features/backend/api_requests/index.dart';
import 'package:hub/features/local/index.dart';
import 'package:hub/features/menu/index.dart';
import 'package:hub/features/module/data/index.dart';
import 'package:hub/features/module/domain/index.dart';
import 'package:hub/features/storage/index.dart';
import 'package:hub/flutter_flow/index.dart' as ff;
import 'package:hub/initialization.dart';
import 'package:hub/main.dart';
import 'package:integration_test/integration_test.dart';
import 'package:material_symbols_icons/symbols.dart';
import 'package:patrol_finders/patrol_finders.dart';
import 'fuzzer/fuzzer.dart';
part 'auth_test.dart';
part 'home_test.dart';
part 'locals_test.dart';
part 'menu_test.dart';
part 'module_test.dart';
part 'notify_test.dart';
part 'profile_test.dart';
part 'property_test.dart';
part 'setting_test.dart';
part 'storage_test.dart';
part 'utils_test.dart';
part 'welcome_test.dart';
late PatrolTester $;
void main() {
//init integration test
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
setUp(() async {});
tearDown(() async {});
// WelcomeTest.signInToSignUp();
// WelcomeTest.signUpToSignIn();
// AuthenticationTest.signIn();
AuthenticationTest.signUp();
// AuthenticationTest.signOut();
//
// ModularizationTest.switchLicense();
// ModularizationTest.containLicense();
//
// MenuTest.navToEntries();
// MenuTest.containEntries();
// MenuTest.labels2AppbarConsistency();
//
// LocalsTest.setLocal();
// LocalsTest.unlinkLocal();
}

View File

@ -0,0 +1,244 @@
part of 'app_test.dart';
class AuthenticationTest {
static Future<void> signIn() async {
patrolWidgetTest(
'Sign-In with fuzzed emails',
(PatrolTester tester) async {
$ = tester;
$.tester
.printToConsole('Authentication Test - Sign-In with fuzzed emails');
final PatrolFinder throwsException = $(Dialog).$(ThrowExceptionWidget);
final Fuzzer fuzzer = Fuzzer(
configs: [
FuzzConfig(
label: 'username',
type: AcceptedTypes.string,
minLength: 5,
maxLength: 10,
),
FuzzConfig(
label: 'domain',
type: AcceptedTypes.string,
minLength: 5,
maxLength: 10,
),
FuzzConfig(
label: 'password',
type: AcceptedTypes.string,
minLength: 5,
maxLength: 10,
),
],
iterations: 10,
);
Map<String, String> concat(
String username, String domain, String password) {
return {
'emailTextFormField': '${username}@${domain}.com',
'passwordTextFormField': password,
};
}
final credentials = fuzzer.fuzz(concat);
await _unlogged();
await $.pumpWidgetAndSettle(const App());
await _navigateToSignIn($);
for (var credential in credentials) {
print('Função: ${credential.functionName}');
print('Entradas: ${credential.inputs}');
print('Saída: ${credential.output}');
print('Mensagem: ${credential.message}');
print('---');
await _auth(credential.output, $, throwsException);
}
},
);
patrolWidgetTest(
'Sign-In with email_app@exemplo.com',
(PatrolTester tester) async {
$ = tester;
$.tester.printToConsole(
'Authentication Test - Sign-In with email_app@exemplo.com');
final PatrolFinder throwsException = $(Dialog).$(ThrowExceptionWidget);
final Map<String, String> credentials = {
'emailTextFormField': 'email_app@exemplo.com',
'passwordTextFormField': '12345678',
};
await _unlogged();
await $.pumpWidgetAndSettle(const App());
await _navigateToSignIn($);
await _auth(credentials, $, throwsException);
},
);
}
static Future<void> signUp() async {
patrolWidgetTest(
'Sign Up - credenciais já registradas',
(PatrolTester tester) async {
$ = tester;
$.tester.printToConsole(
'Authentication Test - Sign-Up: credenciais já registradas');
final PatrolFinder throwsException = $(Dialog).$(ThrowExceptionWidget);
final Map<String, String> credentials = {
'nameTextFormField': 'app',
'emailTextFormField': 'email_app@exemplo.com',
'passwordTextFormField': '12345678',
};
await _unlogged();
await $.pumpWidgetAndSettle(const App());
await _navigateToSignUp($);
await _auth(credentials, $, throwsException);
await Future.delayed(const Duration(milliseconds: 500));
},
);
patrolWidgetTest(
'Sign Up - credenciais novas',
(PatrolTester tester) async {
$ = tester;
$.tester
.printToConsole('Authentication Test - Sign-Up: credenciais novas');
final PatrolFinder throwsException = $(Dialog).$(ThrowExceptionWidget);
final Fuzzer fuzzer = Fuzzer(
configs: [
FuzzConfig(
label: 'name',
type: AcceptedTypes.string,
minLength: 5,
maxLength: 10,
),
FuzzConfig(
label: 'username',
type: AcceptedTypes.string,
minLength: 5,
maxLength: 10,
),
FuzzConfig(
label: 'domain',
type: AcceptedTypes.string,
minLength: 5,
maxLength: 10,
),
FuzzConfig(
label: 'password',
type: AcceptedTypes.string,
minLength: 8,
maxLength: 10,
),
],
iterations: 10,
);
Map<String, String> concat(
String name, String username, String domain, String password) {
return {
'nameTextFormField': name,
'emailTextFormField': '${username}@${domain}.test',
'passwordTextFormField': password,
};
}
final credentials = fuzzer.fuzz(concat);
await _unlogged();
await $.pumpWidgetAndSettle(const App());
for (var credential in credentials) {
print('Função: ${credential.functionName}');
print('Entradas: ${credential.inputs}');
print('Saída: ${credential.output}');
print('Mensagem: ${credential.message}');
print('---');
await _navigateToSignUp($);
await _auth(credential.output, $, throwsException);
}
},
);
}
static Future<void> signOut() async {
patrolWidgetTest(
'Deslogar da Conta',
(PatrolTester tester) async {
$ = tester;
$.tester.printToConsole(
'Authentication Test - Sign-Out: Deslogar da Conta');
await _logged();
await $.pumpWidget(const App());
await $.waitUntilVisible($(MenuStaggeredView));
await $(Icons.menu_rounded) //
.waitUntilVisible()
.tap();
await $.waitUntilVisible($(MenuListView));
await $(Icons.exit_to_app)
.waitUntilVisible()
.tap(settlePolicy: SettlePolicy.trySettle);
await Future.delayed(const Duration(milliseconds: 500));
},
);
}
static Future<void> recovery() async {}
}
Future<void> _auth(
Map<String, String> credentials,
PatrolTester $,
PatrolFinder throwsException,
) async {
await _enterCredentials(credentials, $);
await _submit('SubmitButtonWidget', $, throwsException);
}
Future<void> _enterCredentials(
Map<String, String> credentials,
PatrolTester $,
) async {
for (var entry in credentials.entries) {
await $(ValueKey(entry.key)) //
.waitUntilVisible()
.enterText(entry.value);
await $.pumpAndSettle();
}
}
Future<void> _submit(
String key, PatrolTester $, PatrolFinder throwsException) async {
await $(ValueKey(key)) //
.waitUntilVisible()
.tap();
if ($(ValueKey('ThrowExceptionWidget')).exists) {
// expect(throwsException, findsOneWidget);
await $(ValueKey('ThrowExceptionWidget')) //
.waitUntilVisible()
.tap();
} else {
_navigateBackUsingSystemGesture();
}
}
String _generateRandomString(int length) {
const chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
final rand = Random();
return List.generate(length, (index) => chars[rand.nextInt(chars.length)])
.join();
}

View File

@ -0,0 +1,138 @@
import 'dart:math';
enum AcceptedTypes {
string,
integer,
float,
stringList,
integerList,
floatList,
}
class FuzzConfig {
final String label;
final AcceptedTypes type;
final int minLength;
final int maxLength;
final num minValue;
final num maxValue;
FuzzConfig({
required this.label,
required this.type,
this.minLength = 1,
this.maxLength = 10,
this.minValue = 0,
this.maxValue = 100,
});
}
class FuzzerResult {
final String functionName;
final List<dynamic> inputs;
final dynamic output;
final String message;
FuzzerResult({
required this.functionName,
required this.inputs,
this.output,
required this.message,
});
}
class Fuzzer {
final List<FuzzConfig> configs;
final int iterations;
final Random _random = Random();
Fuzzer({
required this.configs,
this.iterations = 100,
});
List<FuzzerResult> fuzz(Function fn) {
final results = <FuzzerResult>[];
final parameterCount = configs.length;
for (int i = 0; i < iterations; i++) {
final inputs = _generateInputs(parameterCount);
try {
final output = Function.apply(fn, inputs);
results.add(FuzzerResult(
functionName: fn.toString(),
inputs: inputs,
output: output,
message: 'Execução bem-sucedida.',
));
} catch (e) {
results.add(FuzzerResult(
functionName: fn.toString(),
inputs: inputs,
message: 'Erro: $e',
));
}
}
return results;
}
List<dynamic> _generateInputs(int count) {
return List.generate(count, (index) {
final config = configs[index];
return _generateValue(config);
});
}
dynamic _generateValue(FuzzConfig config) {
switch (config.type) {
case AcceptedTypes.string:
final length =
_random.nextInt(config.maxLength - config.minLength + 1) +
config.minLength;
return _generateRandomString(length);
case AcceptedTypes.integer:
return _random.nextInt(
config.maxValue.toInt() - config.minValue.toInt() + 1) +
config.minValue.toInt();
case AcceptedTypes.float:
return _random.nextDouble() * (config.maxValue - config.minValue) +
config.minValue;
case AcceptedTypes.stringList:
final length =
_random.nextInt(config.maxLength - config.minLength + 1) +
config.minLength;
return List.generate(
length, (_) => _generateRandomString(_random.nextInt(10) + 1));
case AcceptedTypes.integerList:
final length =
_random.nextInt(config.maxLength - config.minLength + 1) +
config.minLength;
return List.generate(
length,
(_) =>
_random.nextInt(
config.maxValue.toInt() - config.minValue.toInt() + 1) +
config.minValue.toInt());
case AcceptedTypes.floatList:
final length =
_random.nextInt(config.maxLength - config.minLength + 1) +
config.minLength;
return List.generate(
length,
(_) =>
_random.nextDouble() * (config.maxValue - config.minValue) +
config.minValue);
}
}
String _generateRandomString(int length) {
const chars =
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
return String.fromCharCodes(
Iterable.generate(
length,
(_) => chars.codeUnitAt(_random.nextInt(chars.length)),
),
);
}
}

View File

@ -0,0 +1,11 @@
part of 'app_test.dart';
class homeTest {
static Future drawer() async {}
static Future header() async {}
static Future feed() async {}
static Future isLogged() async {}
}

View File

@ -0,0 +1,204 @@
part of 'app_test.dart';
class LocalsTest {
static Future setLocal() async {
patrolWidgetTest(
'Selecionar um local disponível', //
(PatrolTester tester) async {
$ = tester;
$.tester.printToConsole('Locals Test - Selecionar um local disponível');
await _logged(false);
await $.pumpWidgetAndSettle(const App());
await $.waitUntilVisible($(MenuStaggeredView));
await $.waitUntilVisible($(LocalProfileComponentWidget));
final PatrolFinder profileFinder =
$(#AsyncLocalProfileComponentWidget_InkWell);
expect(profileFinder, findsOneWidget);
await $(profileFinder) //
.waitUntilVisible()
.tap();
final PatrolFinder bottomSheetFinder =
await $(BottomArrowLinkedLocalsComponentWidget) //
.waitUntilVisible();
expect(bottomSheetFinder, findsOneWidget);
final PatrolFinder listViewFinder = await $(bottomSheetFinder) //
.$(ListView)
.waitUntilVisible();
expect(listViewFinder, findsOneWidget);
await $.pump(const Duration(milliseconds: 500));
final PatrolFinder entriesFinder = await $(listViewFinder) //
.$(CardItemTemplateComponentWidget)
.waitUntilVisible();
expect(entriesFinder, findsWidgets);
if (entriesFinder.evaluate().isNotEmpty) {
await $(entriesFinder.first) //
.waitUntilVisible()
.tap();
await $.pumpAndSettle();
}
},
);
}
static Future unlinkLocal() async {
patrolWidgetTest('Desvincular do local selecionado', //
(PatrolTester tester) async {
$ = tester;
$.tester.printToConsole('Locals Test - Desvincular do local selecionado');
await _logged();
await $.pumpWidgetAndSettle(const App());
await $.waitUntilVisible($(MenuStaggeredView));
final PatrolFinder gridView = await $(GridView) //
.waitUntilVisible();
final PatrolFinder entries = await $(gridView)
.$(ButtonMenuItem) //
.waitUntilVisible();
await $.pumpAndSettle();
expect(entries, findsWidgets);
final PatrolFinder settings = await $(gridView) //
.$(Icons.settings)
.waitUntilVisible();
expect(settings, findsOneWidget);
await $(settings).tap();
final PatrolFinder unlinkButton = await $(Symbols.digital_out_of_home) //
.waitUntilVisible();
expect(unlinkButton, findsOneWidget);
await $(unlinkButton) //
.waitUntilVisible()
.tap();
final PatrolFinder alertDialog = await $(#AlertDialogKey) //
.waitUntilVisible();
await alertDialog
.$(#AcceptOptionKey) //
.waitUntilVisible()
.tap(settlePolicy: SettlePolicy.noSettle);
await $.pump();
await $.pump(const Duration(seconds: 1));
await $.pump();
final PatrolFinder bottomSheetFinder =
await $(BottomArrowLinkedLocalsComponentWidget) //
.waitUntilVisible();
expect(bottomSheetFinder, findsOneWidget);
final PatrolFinder listViewFinder = await $(bottomSheetFinder) //
.$(ListView)
.waitUntilVisible();
expect(listViewFinder, findsOneWidget);
final PatrolFinder entriesFinder = await $(listViewFinder)
.$(CardItemTemplateComponentWidget)
.waitUntilVisible();
expect(entriesFinder, findsWidgets);
});
patrolWidgetTest(
'Vincular um local desvinculado', //
(PatrolTester tester) async {
$ = tester;
$.tester.printToConsole('Locals Test - Vincular um local desvinculado');
await _logged(false);
await $.pumpWidget(const App());
final PatrolFinder bottomSheetFinder =
await $(BottomArrowLinkedLocalsComponentWidget) //
.waitUntilVisible();
expect(bottomSheetFinder, findsOneWidget);
await $.pump(const Duration(milliseconds: 500));
final PatrolFinder listViewFinder = $(bottomSheetFinder) //
.$(ListView);
expect(listViewFinder, findsOneWidget);
await $.pump(const Duration(milliseconds: 500));
final PatrolFinder entriesFinder = $(listViewFinder) //
.$(CardItemTemplateComponentWidget);
expect(entriesFinder, findsWidgets);
if (entriesFinder.evaluate().isNotEmpty) {
await $(entriesFinder.first).waitUntilVisible().tap();
final PatrolFinder alertDialog = await $(#AlertDialogKey) //
.waitUntilVisible();
await alertDialog
.$(#AcceptOptionKey) //
.waitUntilVisible()
.tap(settlePolicy: SettlePolicy.noSettle);
}
await Future.delayed(const Duration(milliseconds: 500));
// try {
// await $.pumpAndSettle(
// duration: const Duration(seconds: 2),
// phase: EnginePhase.sendSemanticsUpdate,
// timeout: const Duration(seconds: 2),
// );
// throw Exception('Local está vinculado');
// } catch (e) {
// await Future.delayed(const Duration(milliseconds: 500));
// return;
// }
},
);
}
static Future attachLocal() async {
patrolWidgetTest(
'Selecionar um local disponível', //
(PatrolTester tester) async {
$ = tester;
await _logged();
await $.pumpWidget(const App());
late Map<String, String> credentials;
final PatrolFinder throwsException = $('');
var name = ff.randomString(7, 7, true, true, true);
var email = '$name@example.com';
var password = '12345678';
credentials = {
'nameTextFormField': name,
'emailTextFormField': email,
'passwordTextFormField': password
};
await $.pumpWidget(const App());
await _navigateToSignUp($);
await _auth(credentials, $, throwsException);
credentials = {
'emailTextFormField': email,
'passwordTextFormField': password
};
await _auth(credentials, $, throwsException);
await $.pumpAndSettle();
await StorageHelper() //
.set(ProfileStorageKey.clientUUID.key, '7');
await $.pumpAndSettle();
await Future.delayed(const Duration(milliseconds: 500));
return;
},
);
}
}

View File

@ -0,0 +1,269 @@
part of 'app_test.dart';
class MenuTest {
static Future labels2AppbarConsistency() async {
patrolWidgetTest(
'As labels dos menuItems correspondem aos títulos das AppBars?', //
(PatrolTester tester) async {
$ = tester;
$.tester.printToConsole(
'Menu Test - As labels dos menuItems correspondem aos títulos das AppBars?');
await _logged();
await $.pumpWidgetAndSettle(const App());
await $.waitUntilVisible($(MenuStaggeredView));
await $.waitUntilVisible($(LocalProfileComponentWidget));
final PatrolFinder profileFinder =
await $(#AsyncLocalProfileComponentWidget_InkWell)
.waitUntilVisible();
expect(profileFinder, findsOneWidget);
await $(profileFinder) //
.waitUntilVisible()
.tap();
final PatrolFinder bottomSheetFinder =
await $(BottomArrowLinkedLocalsComponentWidget) //
.waitUntilVisible();
expect(bottomSheetFinder, findsOneWidget);
final PatrolFinder listViewFinder = await $(bottomSheetFinder) //
.$(ListView)
.waitUntilVisible();
expect(listViewFinder, findsOneWidget);
final PatrolFinder entriesFinder = await $(listViewFinder) //
.$(CardItemTemplateComponentWidget)
.waitUntilVisible();
expect(entriesFinder, findsWidgets);
if (entriesFinder.evaluate().isNotEmpty) {
await $(entriesFinder.first) //
.waitUntilVisible()
.tap(settlePolicy: SettlePolicy.noSettle);
}
await $.waitUntilVisible($(MenuStaggeredView));
await $.waitUntilVisible($(LocalProfileComponentWidget));
final List<String> routes = MenuEntry.entries
.where((entry) => entry.key != 'FRE-HUB-LOGOUT')
.map((entry) => entry.route)
.toList();
final List<String> titles = MenuEntry.entries
.where((entry) => entry.key != 'FRE-HUB-LOGOUT')
.map((entry) => entry.name)
.toList();
final LinkedHashMap<String, String> routesTitles = LinkedHashMap //
.fromIterables(routes, titles);
late String route;
late String title;
for (final entry in routesTitles.entries) {
route = entry.key;
title = entry.value;
print('route: $route');
print('title: $title');
if (route == '/petsPage') continue;
if (route == '/fastPassPage') continue;
if (route == '/reservation') continue;
if (route == '/petsOnThePropertyPage') continue;
if (route == '/registerVisitorPage') continue;
if (route == '/messageHistoryPage') continue;
if (route == '/packageOrder') continue;
if (route == '/provisionalHistoryPage') continue;
if (route == '/scheduleCompleteVisitPage') continue;
if (route == '/preferencesSettings') continue;
ff.navigatorKey.currentContext!.go(route);
final PatrolFinder appBar = await $(AppBar) //
.waitUntilExists();
final PatrolFinder titleAppBar = await appBar //
.$(title)
.waitUntilVisible();
expect(titleAppBar, findsOneWidget);
}
},
);
}
static Future containEntries() async {
patrolWidgetTest(
'HomeMenu contém seus itens?', //
(PatrolTester tester) async {
$ = tester;
$.tester.printToConsole('Menu Test - HomeMenu contém seus itens?');
await _logged();
await $.pumpWidgetAndSettle(const App());
await $.waitUntilVisible($(MenuStaggeredView));
await $.waitUntilVisible($(GridView));
final PatrolFinder gridEntries = await $(GridView) //
.$(ButtonMenuItem)
.waitUntilVisible();
expect(gridEntries, findsWidgets);
final List<String?> menuKeys = gridEntries
.evaluate()
.map((element) {
final key = element.widget.key;
if (key is ValueKey<String>) {
return key.value;
}
return null;
})
.where((key) => key != null)
.toList();
await $.pumpAndSettle();
final List<MenuEntry> entries = MenuEntry.entries;
await $.pumpAndSettle();
final List<String> entriesKey = entries
.where((entry) => entry.types.contains(MenuEntryType.Home))
.map((entry) => entry.key)
.toList();
await $.pumpAndSettle();
expect(entriesKey, containsAll(menuKeys));
},
);
patrolWidgetTest(
'DrawerMenu contém seus itens?', //
(PatrolTester tester) async {
$ = tester;
$.tester.printToConsole('Menu Test - DrawerMenu contém seus itens?');
await _logged();
await $.pumpWidgetAndSettle(const App());
await $.waitUntilVisible($(MenuStaggeredView));
await $.waitUntilVisible($(GridView));
final PatrolFinder gridEntries = await $(GridView) //
.$(ButtonMenuItem)
.waitUntilVisible();
expect(gridEntries, findsWidgets);
await $(Icons.menu_rounded).waitUntilVisible().tap();
await $.waitUntilVisible($(ListView));
final PatrolFinder listEntries = await $(ListView) //
.$(CardMenuItem)
.waitUntilVisible();
expect(listEntries, findsWidgets);
final List<String?> menuKeys = listEntries
.evaluate()
.map((element) {
final key = element.widget.key;
if (key is ValueKey<String>) {
return key.value;
}
return null;
})
.where((key) => key != null)
.toList();
await $.pumpAndSettle();
final List<MenuEntry> entries = MenuEntry.entries;
await $.pumpAndSettle();
final List<String> entriesKey = entries
.where((entry) => entry.types.contains(MenuEntryType.Drawer))
.map((entry) => entry.key)
.toList();
await $.pumpAndSettle();
expect(entriesKey, containsAll(menuKeys));
await Future.delayed(const Duration(milliseconds: 500));
},
);
}
static Future navToEntries() async {
patrolWidgetTest(
'Navegação entre items do Menu',
(PatrolTester tester) async {
$ = tester;
$.tester.printToConsole('Menu Test - Navegação entre items do Menu');
await _logged();
await $.pumpWidgetAndSettle(const App());
await $.waitUntilVisible($(MenuStaggeredView));
final PatrolFinder profile =
$(const Key('AsyncLocalProfileComponentWidget_InkWell'));
await $(profile)
.waitUntilVisible()
.tap(settlePolicy: SettlePolicy.noSettle);
await $.waitUntilVisible($(BottomArrowLinkedLocalsComponentWidget));
final PatrolFinder local = $('FRE ACCESS DEMO');
await $(local)
.waitUntilVisible()
.tap(settlePolicy: SettlePolicy.noSettle);
await $.waitUntilVisible($(MenuStaggeredView));
final Finder gridView = find.byType(GridView);
await $.waitUntilVisible(gridView);
final Finder gridEntries = find.descendant(
of: gridView,
matching: find.byType(ButtonMenuItem),
);
await $.pumpAndSettle();
expect(gridEntries, findsWidgets);
final int gridEntriesCount = gridEntries.evaluate().length;
await $.pumpAndSettle();
for (int i = 0; i < gridEntriesCount; i++) {
await $.waitUntilVisible(
$(MenuStaggeredView),
timeout: Duration(seconds: 1),
);
await $.waitUntilVisible(
gridView,
timeout: Duration(seconds: 1),
);
await $.waitUntilVisible(
gridEntries.at(i),
timeout: Duration(seconds: 1),
);
final ButtonMenuItem entry =
$.tester.widget<ButtonMenuItem>(gridEntries.at(i));
final Key? widgetKey = entry.key;
expect(widgetKey, isNotNull);
print('WIDGETKEY = $widgetKey');
if (widgetKey == ValueKey<String>('FRE-HUB-FASTPASS')) continue;
if (widgetKey == ValueKey<String>('FRE-HUB-QRCODE')) continue;
if (widgetKey == ValueKey<String>('FRE-HUB-RESERVATIONS')) continue;
if (widgetKey == ValueKey<String>('FRE-HUB-SETTINGS')) continue;
await $(gridEntries.at(i))
.waitUntilVisible(timeout: const Duration(seconds: 1))
.tap(
settleTimeout: const Duration(seconds: 1),
settlePolicy: SettlePolicy.noSettle,
);
await $.pumpAndSettle(duration: Duration(milliseconds: 500));
await $(Icons.keyboard_arrow_left)
.waitUntilVisible(timeout: const Duration(seconds: 1))
.tap(
settleTimeout: const Duration(seconds: 1),
settlePolicy: SettlePolicy.noSettle,
);
await $.pumpAndSettle(duration: Duration(milliseconds: 500));
}
},
);
}
}

View File

@ -0,0 +1,58 @@
part of 'app_test.dart';
class ModularizationTest {
static Future containLicense() async {
patrolWidgetTest('Os modulos de licença está sendo processados?',
(PatrolTester tester) async {
$ = tester;
$.tester.printToConsole(
'Modularization Test - Os modulos de licença está sendo processados?');
await _logged();
await $.pumpWidgetAndSettle(const App());
await $.waitUntilVisible($(MenuStaggeredView));
final LicenseRepository licenseRepository = LicenseRepositoryImpl();
final List<String> result = await licenseRepository.getLicense();
expect(result, isNotEmpty);
await $.pumpAndSettle();
final List<MenuEntry> entries = MenuEntry.entries;
final List<String> entriesKey = entries
.where((entry) => entry.types.contains(MenuEntryType.Home))
.map((entry) => '{key: ${entry.key}}')
.toList();
expect(result, containsAll(entriesKey));
return;
});
}
static Future switchLicense() async {
patrolWidgetTest(
'Licença está sendo atualizada?',
(PatrolTester tester) async {
$ = tester;
$.tester.printToConsole('Licença está sendo atualizada?');
await _logged();
await $.pumpWidgetAndSettle(const App());
await $.waitUntilVisible($(MenuStaggeredView));
final PatrolFinder profile =
$(const Key('AsyncLocalProfileComponentWidget_InkWell'));
await $(profile)
.waitUntilVisible()
.tap(settlePolicy: SettlePolicy.noSettle);
await $.waitUntilVisible($(BottomArrowLinkedLocalsComponentWidget));
final PatrolFinder local = $('FRE ACCESS DEMO');
await $(local)
.waitUntilVisible()
.tap(settlePolicy: SettlePolicy.trySettle);
},
);
}
}

View File

@ -0,0 +1,3 @@
part of 'app_test.dart';
class notifyTest {}

View File

@ -0,0 +1,27 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:patrol/patrol.dart';
void main() {
patrolTest(
'counter state is the same after going to home and switching apps',
($) async {
// Replace later with your app's main widget
await $.pumpWidgetAndSettle(
MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('app')),
backgroundColor: Colors.blue,
),
),
);
expect($('app'), findsOneWidget);
if (!Platform.isMacOS) {
await $.native.pressHome();
}
},
);
}

View File

@ -0,0 +1 @@
part of 'app_test.dart';

View File

@ -0,0 +1,3 @@
part of 'app_test.dart';
class propertyTest {}

View File

@ -0,0 +1,3 @@
part of 'app_test.dart';
class settingTest {}

View File

@ -0,0 +1,3 @@
part of 'app_test.dart';
class storageTest {}

View File

@ -0,0 +1,86 @@
// GENERATED CODE - DO NOT MODIFY BY HAND AND DO NOT COMMIT TO VERSION CONTROL
// ignore_for_file: type=lint, invalid_use_of_internal_member
import 'dart:async';
import 'package:flutter_test/flutter_test.dart';
import 'package:patrol/patrol.dart';
import 'package:patrol/src/native/contracts/contracts.dart';
import 'package:test_api/src/backend/invoker.dart';
// START: GENERATED TEST IMPORTS
import 'app_test.dart' as app_test;
// END: GENERATED TEST IMPORTS
Future<void> main() async {
// This is the entrypoint of the bundled Dart test.
//
// Its responsibilies are:
// * Running a special Dart test that runs before all the other tests and
// explores the hierarchy of groups and tests.
// * Hosting a PatrolAppService, which the native side of Patrol uses to get
// the Dart tests, and to request execution of a specific Dart test.
//
// When running on Android, the Android Test Orchestrator, before running the
// tests, makes an initial run to gather the tests that it will later run. The
// native side of Patrol (specifically: PatrolJUnitRunner class) is hooked
// into the Android Test Orchestrator lifecycle and knows when that initial
// run happens. When it does, PatrolJUnitRunner makes an RPC call to
// PatrolAppService and asks it for Dart tests.
//
// When running on iOS, the native side of Patrol (specifically: the
// PATROL_INTEGRATION_TEST_IOS_RUNNER macro) makes an initial run to gather
// the tests that it will later run (same as the Android). During that initial
// run, it makes an RPC call to PatrolAppSevice and asks it for Dart tests.
//
// Once the native runner has the list of Dart tests, it dynamically creates
// native test cases from them. On Android, this is done using the
// Parametrized JUnit runner. On iOS, new test case methods are swizzled into
// the RunnerUITests class, taking advantage of the very dynamic nature of
// Objective-C runtime.
//
// Execution of these dynamically created native test cases is then fully
// managed by the underlying native test framework (JUnit on Android, XCTest
// on iOS). The native test cases do only one thing - request execution of the
// Dart test (out of which they had been created) and wait for it to complete.
// The result of running the Dart test is the result of the native test case.
final nativeAutomator = NativeAutomator(config: NativeAutomatorConfig());
await nativeAutomator.initialize();
final binding = PatrolBinding.ensureInitialized(NativeAutomatorConfig());
final testExplorationCompleter = Completer<DartGroupEntry>();
// A special test to explore the hierarchy of groups and tests. This is a hack
// around https://github.com/dart-lang/test/issues/1998.
//
// This test must be the first to run. If not, the native side likely won't
// receive any tests, and everything will fall apart.
test('patrol_test_explorer', () {
// Maybe somewhat counterintuitively, this callback runs *after* the calls
// to group() below.
final topLevelGroup = Invoker.current!.liveTest.groups.first;
final dartTestGroup = createDartTestGroup(topLevelGroup,
tags: null,
excludeTags: null,
);
testExplorationCompleter.complete(dartTestGroup);
print('patrol_test_explorer: obtained Dart-side test hierarchy:');
reportGroupStructure(dartTestGroup);
});
// START: GENERATED TEST GROUPS
group('app_test', app_test.main);
// END: GENERATED TEST GROUPS
final dartTestGroup = await testExplorationCompleter.future;
final appService = PatrolAppService(topLevelDartTestGroup: dartTestGroup);
binding.patrolAppService = appService;
await runAppService(appService);
// Until now, the native test runner was waiting for us, the Dart side, to
// come alive. Now that we did, let's tell it that we're ready to be asked
// about Dart tests.
await nativeAutomator.markPatrolAppServiceReady();
await appService.testExecutionCompleted;
}

View File

@ -0,0 +1,63 @@
part of 'app_test.dart';
Future<void> _logged([bool forceLinkedLocal = true]) async {
await initializeApp();
await StorageHelper() //
.set(SecureStorageKey.isLogged.value, 'true');
await StorageHelper() //
.set(SecureStorageKey.haveLocal.value, 'true');
await StorageHelper() //
.set(ProfileStorageKey.devUUID.key, 'b5c3818753e76d85');
await StorageHelper() //
.set(ProfileStorageKey.userUUID.key, '649c45d7514a28.85876308');
await StorageHelper() //
.set(SecureStorageKey.email.value, 'email_app@exemplo.com');
await StorageHelper() //
.set(SecureStorageKey.password.value, '123456');
await StorageHelper() //
.set(LocalsStorageKey.isNewVersion.key, true);
if (forceLinkedLocal == true) {
await StorageHelper() //
.set(ProfileStorageKey.clientUUID.key, '7');
await PhpGroup //
.resopndeVinculo
.call(tarefa: 'A');
await LicenseRepositoryImpl() //
.resetLicense();
}
}
Future<void> _unlogged() async {
await initializeApp();
await StorageHelper() //
.set(SecureStorageKey.isLogged.value, 'false');
await StorageHelper() //
.set(SecureStorageKey.haveLocal.value, 'false');
await StorageHelper() //
.set(ProfileStorageKey.devUUID.key, '');
await StorageHelper() //
.set(ProfileStorageKey.userUUID.key, '');
await StorageHelper() //
.set(ProfileStorageKey.clientUUID.key, '');
await StorageHelper() //
.set(SecureStorageKey.email.value, '');
await StorageHelper() //
.set(SecureStorageKey.password.value, '');
await StorageHelper() //
.set(LocalsStorageKey.isNewVersion.key, true);
}
Future<void> _navigateToSignIn(PatrolTester $) async {
final signInButton = $(#toggleSignInPage).waitUntilVisible();
await signInButton.tap();
}
Future<void> _navigateToSignUp(PatrolTester $) async {
final signUpButton = $(#toggleSignUpPage).waitUntilVisible();
await signUpButton.tap();
}
Future<void> _navigateBackUsingSystemGesture() async =>
IntegrationTestWidgetsFlutterBinding.instance.keyboard
.isLogicalKeyPressed(LogicalKeyboardKey.escape);

View File

@ -0,0 +1,31 @@
part of 'app_test.dart';
class WelcomeTest {
static Future signInToSignUp() async {
patrolWidgetTest(
'Sign-In to Sign-Up',
(PatrolTester tester) async {
$ = tester;
$.tester.printToConsole('Welcome Test - Sign-In to Sign-Up');
await _unlogged();
await $.pumpWidgetAndSettle(const App());
await _navigateToSignIn($);
await _navigateToSignUp($);
},
);
}
static Future signUpToSignIn() async {
patrolWidgetTest(
'Sign-Up to Sign-In',
(PatrolTester tester) async {
$ = tester;
$.tester.printToConsole('Welcome Test - Sign-Up to Sign-In');
await _unlogged();
await $.pumpWidgetAndSettle(const App());
await _navigateToSignUp($);
await _navigateToSignIn($);
},
);
}
}

View File

@ -7,9 +7,11 @@ class AppBarUtil extends StatelessWidget implements PreferredSizeWidget {
final String title;
final VoidCallback? onBackButtonPressed;
final Widget? actionButton;
final Key appBarKey;
const AppBarUtil({
super.key,
required this.appBarKey,
required this.title,
this.onBackButtonPressed,
this.actionButton,
@ -18,6 +20,7 @@ class AppBarUtil extends StatelessWidget implements PreferredSizeWidget {
@override
Widget build(BuildContext context) {
return AppBar(
key: appBarKey,
backgroundColor: FlutterFlowTheme.of(context).primaryBackground,
automaticallyImplyLeading: false,
forceMaterialTransparency: true,

View File

@ -1,3 +1,5 @@
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:hub/components/organism_components/bottom_arrow_linked_locals_component/bottom_arrow_linked_locals_component_model.dart';
import 'package:hub/components/templates_components/card_item_template_component/card_item_template_component_widget.dart';
@ -202,7 +204,9 @@ class _BottomArrowLinkedLocalsComponentWidgetState
}
Widget _item(BuildContext context, dynamic local) {
log('local: ${local['CLI_NOME']}');
return CardItemTemplateComponentWidget(
key: ValueKey<String>(local['CLI_NOME']),
imagePath: _imagePath(local),
labelsHashMap: _labelsHashMap(local),
statusHashMap: [_statusHashMap(local)],

View File

@ -218,6 +218,7 @@ class _CardItemTemplateComponentWidgetState
@override
Widget build(BuildContext context) {
return InkWell(
key: widget.key,
splashColor: Colors.transparent,
focusColor: Colors.transparent,
hoverColor: Colors.transparent,

View File

@ -1,14 +1,15 @@
import 'package:easy_debounce/easy_debounce.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:hub/flutter_flow/nav/nav.dart';
import 'package:hub/shared/utils/limited_text_size.dart';
import '/flutter_flow/flutter_flow_theme.dart';
import '/flutter_flow/flutter_flow_util.dart';
import '/flutter_flow/flutter_flow_widgets.dart';
import 'package:easy_debounce/easy_debounce.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:google_fonts/google_fonts.dart';
import 'qr_code_pass_key_template_component_model.dart';
export 'qr_code_pass_key_template_component_model.dart';
class QrCodePassKeyTemplateComponentWidget extends StatefulWidget {

View File

@ -7,11 +7,14 @@ import 'sign_in_template_component_widget.dart'
class SignInTemplateComponentModel
extends FlutterFlowModel<SignInTemplateComponentWidget> {
final formKey = GlobalKey<FormState>();
final unfocusNode = FocusNode();
FocusNode? emailAddressFocusNode;
TextEditingController? emailAddressTextController;
String? Function(BuildContext, String?)? emailAddressTextControllerValidator;
SignInTemplateComponentModel();
String? _emailAddressTextControllerValidator(
BuildContext context, String? val) {
if (val == null || val.isEmpty) {
@ -32,6 +35,7 @@ class SignInTemplateComponentModel
TextEditingController? passwordTextController;
late bool passwordVisibility;
String? Function(BuildContext, String?)? passwordTextControllerValidator;
String? _passwordTextControllerValidator(BuildContext context, String? val) {
if (val == null || val.isEmpty) {
return FFLocalizations.of(context).getText(

View File

@ -148,6 +148,7 @@ class AuthenticationService {
await StorageHelper().clean(Storage.databaseStorage);
await StorageHelper().clean(Storage.secureStorage);
DatabaseService.isInitialized = false;
await DatabaseService.instance.init();

View File

@ -18,7 +18,11 @@ const _kPrivateApiFunctionName = 'ffPrivateApiCall';
/// Start PHP Group Code
class PhpGroup {
abstract class Api {
GetLicense getLicense = GetLicense();
}
class PhpGroup extends Api {
static String getBaseUrl() => 'https://freaccess.com.br/freaccess';
static Map<String, String> headers = {};
static LoginCall loginCall = LoginCall();
@ -62,7 +66,7 @@ class PhpGroup {
static GetResidentsByProperty getResidentsByProperty =
GetResidentsByProperty();
static GetOpenedVisits getOpenedVisits = GetOpenedVisits();
static GetLicense getLicense = GetLicense();
GetLicense getLicense = GetLicense();
static GetProvSchedules getProvSchedules = GetProvSchedules();
}

View File

@ -12,7 +12,6 @@ import 'package:hub/flutter_flow/flutter_flow_util.dart';
import 'package:hub/shared/utils/dialog_util.dart';
import 'package:hub/shared/utils/log_util.dart';
import 'package:hub/shared/utils/snackbar_util.dart';
import 'package:rxdart/rxdart.dart';
@immutable
@ -92,6 +91,7 @@ class ProvisionalHistoryState extends State<ProvisionalHistoryPage> {
Widget _backButton(BuildContext context, FlutterFlowTheme theme) {
return FlutterFlowIconButton(
key: ValueKey<String>('BackNavigationAppBar'),
borderColor: Colors.transparent,
borderRadius: 30.0,
borderWidth: 1.0,

View File

@ -11,11 +11,18 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
HomeBloc() : super(HomeState()) {
on<HomeEvent>(_onHomeEvent);
_completer = LocalsRepositoryImpl.license.stream.listen((v) {
add(HomeEvent());
});
}
@override
Future<void> close() {
_completer.cancel();
return super.close();
}
Future<void> _onHomeEvent(HomeEvent event, Emitter<HomeState> emit) async {
final devUUID =
(await StorageHelper().get(ProfileStorageKey.devUUID.key)) ?? '';

View File

@ -2,12 +2,11 @@ import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:hub/features/home/presentation/widgets/drawer_widget.dart';
import 'package:hub/features/local/index.dart';
import 'package:hub/features/menu/index.dart';
import 'package:hub/flutter_flow/flutter_flow_icon_button.dart';
import 'package:hub/flutter_flow/flutter_flow_theme.dart';
import 'package:hub/flutter_flow/flutter_flow_util.dart';
import 'package:hub/features/local/index.dart';
class HomePageWidget extends StatefulWidget {
const HomePageWidget(this.update, {super.key});

View File

@ -25,6 +25,9 @@ class LocalsLocalDataSourceImpl implements LocalsLocalDataSource {
Future<String?> get(String key) async {
final String? local =
await StorageHelper().get(ProfileStorageKey.clientUUID.key);
if (local == null) {
return null;
}
var response = await DatabaseService.database.query(
LocalsConstants.tableLocalsKeychain,
where: 'key = ? AND local = ?',

View File

@ -38,6 +38,12 @@ class LocalProfileBloc extends Bloc<LocalProfileEvent, LocalProfileState> {
});
}
@override
Future<void> close() {
_completer.cancel();
return super.close();
}
Future<void> _onLocalProfileEvent(
LocalProfileEvent event, Emitter<LocalProfileState> emit) async {
final cliName =

View File

@ -87,6 +87,8 @@ class _LocalProfileComponentWidgetState
child: Padding(
padding: const EdgeInsets.all(2.0),
child: InkWell(
key: const Key(
'DefaultLocalProfileComponentWidget_InkWell'),
splashColor: Colors.transparent,
focusColor: Colors.transparent,
hoverColor: Colors.transparent,
@ -180,6 +182,8 @@ class _LocalProfileComponentWidgetState
child: Padding(
padding: const EdgeInsets.all(2.0),
child: InkWell(
key: const Key(
'AsyncLocalProfileComponentWidget_InkWell'),
splashColor: Colors.transparent,
focusColor: Colors.transparent,
hoverColor: Colors.transparent,

View File

@ -9,29 +9,41 @@ import 'package:hub/shared/extensions/dialog_extensions.dart';
import 'package:hub/shared/utils/path_util.dart';
abstract class MenuLocalDataSource {
Future<MenuItem?> addMenuEntry(EnumMenuItem item, List<MenuItem?> entries,
IconData icon, String text, Function() action);
Future<MenuItem?> addMenuEntry(Key key, EnumMenuItem item,
List<MenuItem?> entries, IconData icon, String text, Function() action);
Future<bool> processDisplayDefault(
EnumMenuItem item, MenuEntry opt, List<MenuItem?> entries);
Future<void> handleMenu(EnumMenuItem item, EnumDisplay display, MenuEntry opt,
List<MenuItem?> entries);
Future<bool> processStartDate(String startDate, MenuEntry entry);
Future<bool> processExpirationDate(String expirationDate, MenuEntry entry);
}
class MenuLocalDataSourceImpl implements MenuLocalDataSource {
static final MenuLocalDataSourceImpl _instance =
MenuLocalDataSourceImpl._internal();
factory MenuLocalDataSourceImpl() => _instance;
MenuLocalDataSourceImpl._internal();
@override
Future<MenuItem?> addMenuEntry(EnumMenuItem item, List<MenuItem?> entries,
IconData icon, String text, Function() action) async {
Future<MenuItem?> addMenuEntry(
Key key,
EnumMenuItem item,
List<MenuItem?> entries,
IconData icon,
String text,
Function() action,
) async {
final menuItem = item == EnumMenuItem.button
? ButtonMenuItem(icon: icon, action: action, title: text)
? ButtonMenuItem(key: key, icon: icon, action: action, title: text)
: item == EnumMenuItem.card || item == EnumMenuItem.tile
? CardMenuItem(icon: icon, action: action, title: text)
? CardMenuItem(key: key, icon: icon, action: action, title: text)
: null;
if (menuItem != null) {
entries.add(menuItem);
@ -43,7 +55,9 @@ class MenuLocalDataSourceImpl implements MenuLocalDataSource {
Future<bool> processDisplayDefault(
EnumMenuItem item, MenuEntry opt, List<MenuItem?> entries) async {
if (opt.key == 'FRE-HUB-LOGOUT') {
await addMenuEntry(item, entries, opt.icon, opt.name, () async {
await addMenuEntry(
ValueKey<String>(opt.key), item, entries, opt.icon, opt.name,
() async {
await AuthenticationService.signOut(navigatorKey.currentContext!);
});
return true;
@ -57,12 +71,16 @@ class MenuLocalDataSourceImpl implements MenuLocalDataSource {
try {
switch (display.value) {
case 'VISIVEL':
await addMenuEntry(item, entries, opt.icon, opt.name, () async {
await addMenuEntry(
ValueKey<String>(opt.key), item, entries, opt.icon, opt.name,
() async {
await PathUtil.nav(opt.route);
});
break;
case 'DESABILITADO':
await addMenuEntry(item, entries, opt.icon, opt.name, () async {
await addMenuEntry(
ValueKey<String>(opt.key), item, entries, opt.icon, opt.name,
() async {
await DialogUnavailable.unavailableFeature(
navigatorKey.currentContext!);
});

View File

@ -2,24 +2,24 @@ import 'dart:developer';
import 'package:hub/features/menu/index.dart';
import 'package:hub/features/module/index.dart';
import 'package:hub/features/storage/index.dart';
import 'package:hub/flutter_flow/custom_functions.dart';
class MenuRepositoryImpl implements MenuRepository {
final MenuLocalDataSource menuDataSource = MenuLocalDataSourceImpl();
@override
Future<List<MenuItem?>> generateMenuEntries(
List<MenuEntry> menuEntries, EnumMenuItem item) async {
Future<List<MenuItem?>> entries2Items(
List<MenuEntry> menuEntries, EnumMenuItem menuItem) async {
List<MenuItem?> entries = [];
// final bool isNewVersion = await StorageHelper().get(KeychainStorageKey.isNewVersion.value).then((v) => v.toBoolean());
try {
for (var entry in menuEntries) {
final bool isDefault =
await menuDataSource.processDisplayDefault(item, entry, entries);
final bool isDefault = await menuDataSource.processDisplayDefault(
menuItem, entry, entries);
if (isDefault) continue;
final licenseValue =
await LicenseRepositoryImpl().getLicense(entry.key);
final licenseValue = await LicenseRepositoryImpl().getModule(entry.key);
if (licenseValue != null) {
final licenseMap = await stringToMap(licenseValue);
final display = EnumDisplay.fromString(licenseMap['display']);
@ -30,17 +30,17 @@ class MenuRepositoryImpl implements MenuRepository {
final isExpired =
await menuDataSource.processExpirationDate(expirationDate, entry);
if (isStarted && !isExpired) {
await menuDataSource.handleMenu(item, display, entry, entries);
await menuDataSource.handleMenu(menuItem, display, entry, entries);
}
if (isExpired) {
log('Entry ${entry.key} is expired');
await menuDataSource.handleMenu(
item, EnumDisplay.inactive, entry, entries);
menuItem, EnumDisplay.inactive, entry, entries);
}
if (!isStarted) {
log('Entry ${entry.key} is not started');
await menuDataSource.handleMenu(
item, EnumDisplay.inactive, entry, entries);
menuItem, EnumDisplay.inactive, entry, entries);
}
}
}
@ -55,7 +55,7 @@ class MenuRepositoryImpl implements MenuRepository {
if (await _shouldUpdateDisplay(module, isNewVersion)) {
final displayValue =
module['display'] == EnumDisplay.active ? 'VISIVEL' : 'INVISIVEL';
await LicenseLocalDataSourceImpl()
await LicenseLocalDataSourceImpl(DatabaseService.database)
.setDisplayByKey(['FRE-HUB-ABOUT-PROPERTY'], displayValue);
return EnumDisplay.fromString(displayValue);
}

View File

@ -1,6 +1,6 @@
import 'package:hub/features/menu/index.dart';
abstract class MenuRepository {
Future<List<MenuItem?>> generateMenuEntries(
Future<List<MenuItem?>> entries2Items(
List<MenuEntry> menuEntries, EnumMenuItem item);
}

View File

@ -1,9 +1,10 @@
import 'dart:async';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:hub/features/backend/index.dart';
import 'package:hub/features/local/index.dart';
import 'package:hub/features/menu/index.dart';
import 'package:hub/features/module/index.dart';
import 'package:hub/features/local/index.dart';
class MenuEvent {}
@ -36,10 +37,10 @@ class MenuBloc extends Bloc<MenuEvent, MenuState> {
}
Future<void> _onMenuEvent(MenuEvent event, Emitter<MenuState> emit) async {
await LicenseRemoteDataSourceImpl().waitForSaveCompletion();
await LicenseRemoteDataSourceImpl(PhpGroup()).waitForSaveCompletion();
final List<MenuItem?> newEntries =
await MenuRepositoryImpl().generateMenuEntries(entries, item);
await MenuRepositoryImpl().entries2Items(entries, item);
emit(state.copyWith(menuEntries: newEntries));
}

View File

@ -37,7 +37,7 @@ class MenuEntry implements BaseModule {
icon: Icons.sports_motorsports_outlined,
name: FFLocalizations.of(navigatorKey.currentContext!).getVariableText(
ptText: 'Agendar Entregas',
enText: 'Schedule Delivery',
enText: 'Delivery Schedule',
),
route: '/deliverySchedule',
types: [MenuEntryType.Home, MenuEntryType.Drawer],

View File

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:hub/features/menu/index.dart';
import 'package:hub/flutter_flow/flutter_flow_theme.dart';
import 'package:hub/flutter_flow/flutter_flow_util.dart';
class CardMenuItem extends MenuItem {
const CardMenuItem({
@ -35,11 +36,11 @@ class _MenuCardItemState extends State<CardMenuItem> {
onTap: _isProcessing
? null
: () async {
setState(() {
safeSetState(() {
_isProcessing = true;
});
await widget.action.call();
setState(() {
safeSetState(() {
_isProcessing = false;
});
},

View File

@ -1,21 +1,41 @@
import 'dart:developer';
import 'package:hub/features/module/index.dart';
import 'package:hub/features/storage/index.dart';
import 'package:hub/shared/extensions/string_extensions.dart';
import 'package:sqflite/sqflite.dart';
abstract class LicenseLocalDataSource {
Future<void> init();
Future<void> setDisplayByKey(final List<String> key, final String display);
Future<bool> isNewVersion();
Future<String?> get(String key);
Future<void> set<T>(String key, T value);
Future<bool> set<T>(String key, T value);
Future<void> del(String key);
Future<bool> setupLicense(bool isNewVersion);
Future<List<String>> getLicense();
Future<void> clear();
}
class LicenseLocalDataSourceImpl implements LicenseLocalDataSource {
Database? _database;
static final LicenseLocalDataSourceImpl _instance =
LicenseLocalDataSourceImpl._internal();
factory LicenseLocalDataSourceImpl() => _instance;
factory LicenseLocalDataSourceImpl(Database database) {
_instance._database ??= database;
return _instance;
}
LicenseLocalDataSourceImpl._internal();
@override
@ -23,6 +43,38 @@ class LicenseLocalDataSourceImpl implements LicenseLocalDataSource {
await DatabaseService.instance.init();
}
@override
Future<bool> setupLicense(bool isNewVersion) async {
log('Setting up license...');
try {
final License license = await License.getLicense(isNewVersion);
final List<String> inactiveModuleKey = license.modules
.where((module) => module.display == ModuleStatus.inactive.key)
.map((module) => module.key)
.toList();
final List<String> activeModuleKey = license.modules
.where((module) => module.display == ModuleStatus.active.key)
.map((module) => module.key)
.toList();
final List<String> disabledModuleKey = license.modules
.where((module) => module.display == ModuleStatus.disabled.key)
.map((module) => module.key)
.toList();
await setDisplayByKey(inactiveModuleKey, 'INVISIVEL');
await setDisplayByKey(activeModuleKey, 'VISIVEL');
await setDisplayByKey(disabledModuleKey, 'DESABILITADO');
return true;
} catch (e, s) {
log('Erro ao configurar licenças: $e', stackTrace: s);
return false;
}
}
@override
Future<void> setDisplayByKey(
final List<String> keys, final String display) async {
@ -48,9 +100,9 @@ class LicenseLocalDataSourceImpl implements LicenseLocalDataSource {
@override
Future<String?> get(String key) async {
var response = await DatabaseService.database
.query(tableLicense, where: 'key = ?', whereArgs: [key]);
if (response.isEmpty) {
var response = await _instance._database
?.query(tableLicense, where: 'key = ?', whereArgs: [key]);
if (response!.isEmpty) {
return null;
}
@ -58,12 +110,12 @@ class LicenseLocalDataSourceImpl implements LicenseLocalDataSource {
}
@override
Future<void> set<T>(String key, T value) async {
Future<bool> set<T>(String key, T value) async {
value as Map<String, dynamic>;
if (value.isEmpty) return;
if (key == 'null') return;
if (value.isEmpty) return false;
if (key == 'null') return false;
await DatabaseService.database.rawInsert(
await _instance._database?.rawInsert(
'INSERT OR REPLACE INTO $tableLicense (key, display, expirationDate, startDate, quantity) VALUES (?, ?, ?, ?, ?)',
[
key,
@ -73,17 +125,27 @@ class LicenseLocalDataSourceImpl implements LicenseLocalDataSource {
value['quantity']
],
);
return;
return true;
}
@override
Future<void> del(String key) async {
await DatabaseService.database
.delete(tableLicense, where: 'key = ?', whereArgs: [key]);
await _instance._database
?.delete(tableLicense, where: 'key = ?', whereArgs: [key]);
}
@override
Future<void> clear() async {
await DatabaseService.database.delete(tableLicense);
await _instance._database?.delete(tableLicense);
}
@override
Future<List<String>> getLicense() async {
var response =
await _instance._database?.query(tableLicense, columns: ['key']);
if (response!.isEmpty) {
return [];
}
return response.map((e) => e.toString()).toList();
}
}

View File

@ -6,60 +6,36 @@ import 'dart:developer';
import 'package:hub/features/backend/index.dart';
import 'package:hub/features/local/data/repositories/locals_repository_impl.dart';
import 'package:hub/features/module/index.dart';
import 'package:sqflite/sqflite.dart';
abstract class LicenseRemoteDataSource {
Future<bool> fetchLicenses(bool isNewVersion);
Future<void> cleanLicense();
Future<bool> cleanLicense();
Future<void> processLicense();
Future<bool> setupLicense(Database database, bool isNewVersion);
}
class LicenseRemoteDataSourceImpl implements LicenseRemoteDataSource {
Api? _api;
static final LicenseRemoteDataSourceImpl _instance =
LicenseRemoteDataSourceImpl._internal();
factory LicenseRemoteDataSourceImpl() => _instance;
factory LicenseRemoteDataSourceImpl(Api api) {
_instance._api ??= api;
return _instance;
}
LicenseRemoteDataSourceImpl._internal();
@override
Future<void> processLicense() async {}
@override
Future<void> cleanLicense() async {
LocalsRepositoryImpl.license.add(false);
}
@override
Future<bool> setupLicense(Database database, bool isNewVersion) async {
log('Setting up license...');
Future<bool> cleanLicense() async {
try {
final License license = await License.getLicense(isNewVersion);
final List<String> inactiveModuleKey = license.modules
.where((module) => module.display == ModuleStatus.inactive.key)
.map((module) => module.key)
.toList();
final List<String> activeModuleKey = license.modules
.where((module) => module.display == ModuleStatus.active.key)
.map((module) => module.key)
.toList();
final List<String> disabledModuleKey = license.modules
.where((module) => module.display == ModuleStatus.disabled.key)
.map((module) => module.key)
.toList();
await LicenseLocalDataSourceImpl()
.setDisplayByKey(inactiveModuleKey, 'INVISIVEL');
await LicenseLocalDataSourceImpl()
.setDisplayByKey(activeModuleKey, 'VISIVEL');
await LicenseLocalDataSourceImpl()
.setDisplayByKey(disabledModuleKey, 'DESABILITADO');
LocalsRepositoryImpl.license.add(false);
return true;
} catch (e, s) {
log('Erro ao configurar licenças: $e', stackTrace: s);
log('Erro ao limpar licenças: $e', stackTrace: s);
return false;
}
}
@ -68,8 +44,8 @@ class LicenseRemoteDataSourceImpl implements LicenseRemoteDataSource {
Future<bool> fetchLicenses(bool isNewVersion) async {
log('Fetching licenses...');
try {
final response = await PhpGroup.getLicense();
final dynamic responseBody = response.jsonBody;
final response = await _instance._api?.getLicense();
final dynamic responseBody = response!.jsonBody;
if (responseBody == []) {
return true;
@ -108,6 +84,6 @@ class LicenseRemoteDataSourceImpl implements LicenseRemoteDataSource {
static Future<void> _saveModule(final dynamic body) async {
if (body is! Map<String, dynamic>) return;
await LicenseRepositoryImpl().setLicense(body['key'], body);
await LicenseRepositoryImpl().setModule(body['key'], body);
}
}

View File

@ -5,44 +5,65 @@ import 'package:hub/features/module/domain/index.dart';
import 'package:hub/features/storage/index.dart';
import 'package:sqflite/sqflite.dart';
import '../../../backend/index.dart';
typedef LicenseStatus = bool;
class LicenseRepositoryImpl implements LicenseRepository {
final LicenseLocalDataSource localDataSource = LicenseLocalDataSourceImpl();
final LicenseRemoteDataSource remoteDataSource =
LicenseRemoteDataSourceImpl();
final Database database = DatabaseService.database;
late final Database database;
late final Api api;
late final LicenseLocalDataSource localDataSource;
late final LicenseRemoteDataSource remoteDataSource;
LicenseRepositoryImpl();
LicenseRepositoryImpl([Database? database, Api? api])
: database = database ?? DatabaseService.database,
api = api ?? PhpGroup() {
localDataSource = LicenseLocalDataSourceImpl(this.database);
remoteDataSource = LicenseRemoteDataSourceImpl(this.api);
}
@override
Future<bool> updateLicense() async {
log('updateLicense');
bool result = false;
final bool isNewVersion = await localDataSource.isNewVersion();
if (isNewVersion) {
await remoteDataSource.setupLicense(database, isNewVersion);
await localDataSource.setupLicense(isNewVersion);
result = await remoteDataSource.fetchLicenses(isNewVersion);
} else {
result = await remoteDataSource.setupLicense(database, isNewVersion);
result = await localDataSource.setupLicense(isNewVersion);
}
return result;
}
@override
Future<void> cleanLicense() async {
Future<bool> cleanLicense() async {
return await remoteDataSource.cleanLicense();
}
@override
Future<String?> getLicense(String key) async {
Future<String?> getModule(String key) async {
final response = await localDataSource.get(key);
return response;
}
@override
Future<void> setLicense<T>(String key, T value) async {
Future<bool> setModule<T>(String key, T value) async {
return await localDataSource.set(key, value);
}
@override
Future<List<String>> getLicense() async {
return await localDataSource.getLicense();
}
@override
Future<bool> resetLicense() async {
bool result = false;
final bool isNewVersion = await localDataSource.isNewVersion();
result = await localDataSource.setupLicense(isNewVersion);
return result;
}
}

View File

@ -1,7 +1,13 @@
abstract class LicenseRepository {
Future<bool> updateLicense();
Future<void> cleanLicense();
Future<String?> getLicense(String key);
Future<void> setLicense<T>(String key, T value);
Future<bool> cleanLicense();
Future<bool> resetLicense();
Future<String?> getModule(String key);
Future<bool> setModule<T>(String key, T value);
Future<List<String>> getLicense();
}

View File

@ -2,7 +2,6 @@
import 'package:flutter/material.dart';
import 'package:hub/components/atomic_components/shared_components_atoms/appbar.dart';
import 'package:hub/features/menu/index.dart';
import 'package:hub/flutter_flow/flutter_flow_model.dart';
import 'package:hub/flutter_flow/flutter_flow_theme.dart';
import 'package:hub/flutter_flow/flutter_flow_util.dart';
import 'package:hub/flutter_flow/nav/nav.dart';
@ -71,6 +70,8 @@ class _AboutPropertyPageState extends State<AboutPropertyPage>
final String title = FFLocalizations.of(context).getVariableText(
ptText: "Sobre a Propriedade", enText: "About the Property");
return AppBarUtil(
key: UniqueKey(),
appBarKey: ValueKey<String>('BackNavigationAppBar'),
title: title,
onBackButtonPressed: () => context.pop(),
);

View File

@ -33,6 +33,7 @@ class DatabaseService {
onOpen: _onOpen,
onConfigure: _onConfigure,
);
print('Database initialized');
await LicenseRepositoryImpl().updateLicense();
isInitialized = true;
}

View File

@ -390,6 +390,7 @@ String formatNumber(
}
DateTime get getCurrentTimestamp => DateTime.now();
DateTime dateTimeFromSecondsSinceEpoch(int seconds) {
return DateTime.fromMillisecondsSinceEpoch(seconds * 1000);
}
@ -400,8 +401,11 @@ extension DateTimeConversionExtension on DateTime {
extension DateTimeComparisonOperators on DateTime {
bool operator <(DateTime other) => isBefore(other);
bool operator >(DateTime other) => isAfter(other);
bool operator <=(DateTime other) => this < other || isAtSameMomentAs(other);
bool operator >=(DateTime other) => this > other || isAtSameMomentAs(other);
}
@ -457,14 +461,18 @@ Rect? getWidgetBoundingBox(BuildContext context) {
}
bool get isAndroid => !kIsWeb && Platform.isAndroid;
bool get isiOS => !kIsWeb && Platform.isIOS;
bool get isWeb => kIsWeb;
const kBreakpointSmall = 479.0;
const kBreakpointMedium = 767.0;
const kBreakpointLarge = 991.0;
bool isMobileWidth(BuildContext context) =>
MediaQuery.sizeOf(context).width < kBreakpointSmall;
bool responsiveVisibility({
required BuildContext context,
bool phone = true,
@ -493,6 +501,7 @@ const kTextValidatorWebsiteRegex =
extension FFTextEditingControllerExt on TextEditingController? {
String get text => this == null ? '' : this!.text;
set text(String newText) => this?.text = newText;
}
@ -574,6 +583,7 @@ void showAlertDialog(BuildContext context, String title, String content,
context: context,
builder: (context) {
return AlertDialog(
key: ValueKey<String>('AlertDialogKey'),
backgroundColor: FlutterFlowTheme.of(context).primaryBackground,
title: Text(title,
style: TextStyle(
@ -593,6 +603,7 @@ void showAlertDialog(BuildContext context, String title, String content,
mainAxisSize: MainAxisSize.max,
children: [
FFButtonWidget(
key: ValueKey<String>('RejectOptionKey'),
onPressed: () => context.pop(), //Navigator.pop(context),
options: FFButtonOptions(
width: MediaQuery.of(context).size.width * 0.3,
@ -615,6 +626,7 @@ void showAlertDialog(BuildContext context, String title, String content,
),
),
FFButtonWidget(
key: ValueKey<String>('AcceptOptionKey'),
onPressed: () async {
action();
},
@ -707,6 +719,7 @@ extension StatefulWidgetExtensions on State<StatefulWidget> {
// For iOS 16 and below, set the status bar color to match the app's theme.
// https://github.com/flutter/flutter/issues/41067
Brightness? _lastBrightness;
void fixStatusBarOniOS16AndBelow(BuildContext context) {
if (!isiOS) {
return;

View File

@ -15,20 +15,25 @@ class FFLocalizations {
static List<String> languages() => ['pt', 'en'];
static late SharedPreferences _prefs;
static Future initialize() async =>
_prefs = await SharedPreferences.getInstance();
static Future storeLocale(String locale) =>
_prefs.setString(_kLocaleStorageKey, locale);
static Locale? getStoredLocale() {
final locale = _prefs.getString(_kLocaleStorageKey);
return locale != null && locale.isNotEmpty ? createLocale(locale) : null;
}
String get languageCode => locale.toString();
String? get languageShortCode =>
_languagesWithShortCode.contains(locale.toString())
? '${locale.toString()}_short'
: null;
int get languageIndex => languages().contains(languageCode)
? languages().indexOf(languageCode)
: 0;
@ -443,7 +448,7 @@ final kTranslationsMap = <Map<String, Map<String, String>>>[
},
'784f83pc': {
'pt': 'Consultar Liberações',
'en': 'Liberation History',
'en': 'Liberations History',
},
'1skj43ye': {
'pt': 'Home',

View File

@ -126,7 +126,7 @@ GoRouter createRouter(AppStateNotifier appStateNotifier) {
)
: const ReceptionPageWidget();
} else {
return const WelcomePageWidget();
return const WelcomePage();
}
}(),
builder: (context, snapshot) {
@ -134,7 +134,7 @@ GoRouter createRouter(AppStateNotifier appStateNotifier) {
return const Center(child: CircularProgressIndicator());
} else if (snapshot.hasError) {
DialogUtil.error(context, snapshot.error.toString());
return const WelcomePageWidget();
return const WelcomePage();
} else {
return snapshot.data!;
}
@ -273,7 +273,7 @@ GoRouter createRouter(AppStateNotifier appStateNotifier) {
FFRoute(
name: 'welcomePage',
path: '/welcomePage',
builder: (context, params) => const WelcomePageWidget()),
builder: (context, params) => const WelcomePage()),
FFRoute(
name: 'qrCodePage',
path: '/qrCodePage',

View File

@ -23,39 +23,58 @@ Future<void> initializeApp() async {
_initializeUrlStrategy();
_initializeSystemSettings();
await _initializeFlutterFlow();
await _initializeNav();
}
Future<void> _initializeTracking() async {
print('Requesting tracking authorization...');
await AppTrackingTransparency.requestTrackingAuthorization();
print('Tracking authorization requested');
}
Future<void> _initializeFirebase() async {
print('Initializing Firebase...');
await Firebase.initializeApp();
print('Firebase initialized');
}
Future<void> _initializeNotificationService() async {
print('Initializing Notification Service...');
await NotificationService.initialize();
print('Notification Service initialized');
}
void _initializeUrlStrategy() {
print('Initializing URL Strategy...');
setUrlStrategy(PathUrlStrategy());
print('URL Strategy initialized');
}
void _initializeSystemSettings() {
print('Initializing System Settings...');
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
if (kDebugMode) {
log("Aplicativo em Debug Mode, crashlytics desabilitado!");
print('Debug mode');
} else {
final crashlyticsInstance = FirebaseCrashlytics.instance;
print('Release mode');
if (crashlyticsInstance.isCrashlyticsCollectionEnabled) {
FlutterError.onError = crashlyticsInstance.recordFlutterError;
print('Crashlytics enabled');
}
}
}
Future<void> _initializeFlutterFlow() async {
print('Initializing FlutterFlow...');
await FlutterFlowTheme.initialize();
await FFLocalizations.initialize();
print('FlutterFlow initialized');
}
Future<void> _initializeNav() async {
print('Initializing Nav...');
GoRouter.optionURLReflectsImperativeAPIs = true;
usePathUrlStrategy();
print('Nav initialized');
}

View File

@ -8,14 +8,14 @@ import 'package:firebase_crashlytics/firebase_crashlytics.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:hub/features/notification/index.dart';
import 'package:hub/features/storage/index.dart';
import 'package:hub/flutter_flow/flutter_flow_theme.dart';
import 'package:hub/flutter_flow/internationalization.dart';
import 'package:hub/flutter_flow/nav/nav.dart';
import 'package:hub/shared/utils/test_util.dart';
import 'package:responsive_framework/responsive_framework.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'initialization.dart';
@ -175,11 +175,13 @@ class _AppState extends State<App> {
_router = createRouter(_appStateNotifier);
Future.delayed(
const Duration(milliseconds: 1000),
() => setState(() => _appStateNotifier.stopShowingSplashImage()),
() => mounted
? setState(() => _appStateNotifier.stopShowingSplashImage())
: null,
);
_setupFirebaseMessaging();
DeepLinkService().ensureInitialization();
if (TestUtil.isInTest) DeepLinkService().ensureInitialization();
}
@override

View File

@ -36,6 +36,7 @@ class _DeliveryScheduleState extends State<DeliverySchedule> {
automaticallyImplyLeading: false,
forceMaterialTransparency: true,
leading: FlutterFlowIconButton(
key: ValueKey<String>('BackNavigationAppBar'),
borderColor: Colors.transparent,
borderRadius: 30.0,
borderWidth: 1.0,

View File

@ -13,7 +13,6 @@ import 'package:hub/shared/utils/dialog_util.dart';
import 'package:hub/shared/utils/limited_text_size.dart';
import 'package:hub/shared/utils/log_util.dart';
import 'package:hub/shared/utils/snackbar_util.dart';
import 'package:hub/shared/utils/validator_util.dart';
class LiberationHistoryWidget extends StatefulWidget {
@ -104,6 +103,7 @@ class _LiberationHistoryWidgetState extends State<LiberationHistoryWidget> {
automaticallyImplyLeading: false,
forceMaterialTransparency: true,
leading: FlutterFlowIconButton(
key: ValueKey<String>('BackNavigationAppBar'),
borderColor: Colors.transparent,
borderRadius: 30.0,
borderWidth: 1.0,
@ -332,13 +332,13 @@ class _LiberationHistoryWidgetState extends State<LiberationHistoryWidget> {
Future<ApiCallResponse?> _fetchRequests() async {
try {
setState(() => _loading = true);
safeSetState(() => _loading = true);
var response = await PhpGroup.getLiberationsCall.call().first;
final List<dynamic> requests = response.jsonBody['solicitacoes'] ?? [];
if (requests.isNotEmpty) {
setState(() {
safeSetState(() {
_requestWrap.addAll(requests);
_hasData = true;
_loading = false;
@ -349,7 +349,7 @@ class _LiberationHistoryWidgetState extends State<LiberationHistoryWidget> {
_showNoMoreDataSnackBar(context);
setState(() {
safeSetState(() {
_hasData = false;
_loading = false;
});
@ -359,7 +359,7 @@ class _LiberationHistoryWidgetState extends State<LiberationHistoryWidget> {
await DialogUtil.errorDefault(context);
LogUtil.requestAPIFailed(
"proccessRequest.php", "", "Consulta de Solicitações", e, s);
setState(() {
safeSetState(() {
_hasData = false;
_loading = false;
});

View File

@ -146,6 +146,7 @@ class _MessageHistoryPageWidgetState extends State<MessageHistoryPageWidget>
backgroundColor: FlutterFlowTheme.of(context).primaryBackground,
automaticallyImplyLeading: false,
leading: FlutterFlowIconButton(
key: ValueKey<String>('BackNavigationAppBar'),
borderColor: Colors.transparent,
borderRadius: 30.0,
borderWidth: 1.0,

View File

@ -10,11 +10,9 @@ import 'package:hub/features/storage/index.dart';
import 'package:hub/flutter_flow/flutter_flow_icon_button.dart';
import 'package:hub/flutter_flow/flutter_flow_theme.dart';
import 'package:hub/flutter_flow/flutter_flow_util.dart';
import 'package:hub/shared/utils/dialog_util.dart';
import 'package:hub/shared/utils/limited_text_size.dart';
import 'package:hub/shared/utils/log_util.dart';
import 'package:hub/shared/utils/validator_util.dart';
import 'package:rxdart/rxdart.dart';
@ -145,6 +143,7 @@ class _PackageOrderPage extends State<PackageOrderPage> {
Widget _backButton(BuildContext context, FlutterFlowTheme theme) {
return FlutterFlowIconButton(
key: ValueKey<String>('BackNavigationAppBar'),
borderColor: Colors.transparent,
borderRadius: 30.0,
borderWidth: 1.0,

View File

@ -47,6 +47,7 @@ class _PeopleOnThePropertyPageState extends State<PeopleOnThePropertyPage> {
automaticallyImplyLeading: false,
forceMaterialTransparency: true,
leading: FlutterFlowIconButton(
key: ValueKey<String>('BackNavigationAppBar'),
borderColor: Colors.transparent,
borderRadius: 30.0,
borderWidth: 1.0,

View File

@ -1,15 +1,12 @@
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:hub/components/templates_components/card_item_template_component/card_item_template_component_widget.dart';
import 'package:hub/features/backend/index.dart';
import 'package:hub/features/storage/index.dart';
import 'package:hub/flutter_flow/flutter_flow_icon_button.dart';
import 'package:hub/flutter_flow/flutter_flow_theme.dart';
import 'package:hub/flutter_flow/flutter_flow_util.dart';
import 'package:hub/pages/pets_page/pets_page_model.dart';
import 'package:hub/shared/utils/dialog_util.dart';
import 'package:hub/shared/utils/limited_text_size.dart';
import 'package:hub/shared/utils/log_util.dart';
@ -85,6 +82,7 @@ class _PetsHistoryScreenState extends State<PetsHistoryScreen>
Widget _backButton(BuildContext context, FlutterFlowTheme theme) {
return FlutterFlowIconButton(
key: ValueKey<String>('BackNavigationAppBar'),
borderColor: Colors.transparent,
borderRadius: 30.0,
borderWidth: 1.0,

View File

@ -1,5 +1,4 @@
import 'dart:convert';
import 'dart:developer';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
@ -13,7 +12,6 @@ import 'package:hub/flutter_flow/flutter_flow_widgets.dart';
import 'package:hub/flutter_flow/form_field_controller.dart';
import 'package:hub/flutter_flow/nav/nav.dart';
import 'package:hub/pages/pets_page/pets_page_widget.dart';
import 'package:hub/shared/utils/dialog_util.dart';
import 'package:hub/shared/utils/image_util.dart';
import 'package:hub/shared/utils/limited_text_size.dart';
@ -110,7 +108,8 @@ class PetsPageModel extends FlutterFlowModel<PetsPageWidget> {
String? Function(BuildContext, String?)? textControllerObservationValidator;
Future<void> initAsync() async {
defaultDropDownText = FFLocalizations.of(buildContext!).getVariableText(
defaultDropDownText =
FFLocalizations.of(navigatorKey.currentContext!).getVariableText(
enText: 'Select an option',
ptText: 'Selecione uma opção',
);

View File

@ -76,6 +76,8 @@ class _PetsPageWidgetState extends State<PetsPageWidget>
PreferredSizeWidget _buildAppBar(BuildContext context) {
return AppBarUtil(
key: UniqueKey(),
appBarKey: ValueKey<String>('BackNavigationAppBar'),
title: FFLocalizations.of(context).getVariableText(
ptText: 'Cadastrar Pets',
enText: 'Pets Register',

View File

@ -1,15 +1,13 @@
import 'dart:async';
import 'dart:isolate';
import 'package:flutter/material.dart';
import 'package:hub/components/templates_components/change_passs_qr_code_pass_key_template_component/change_pass_widget.dart';
import 'package:hub/features/auth/index.dart';
import 'package:hub/features/backend/index.dart';
import 'package:hub/features/local/index.dart';
import 'package:hub/features/storage/index.dart';
import 'package:hub/flutter_flow/flutter_flow_util.dart';
import 'package:hub/flutter_flow/nav/nav.dart';
import 'package:hub/features/local/index.dart';
import 'package:hub/shared/utils/path_util.dart';
import 'package:share_plus/share_plus.dart';

View File

@ -1,15 +1,12 @@
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:hub/features/local/data/index.dart';
import 'package:hub/flutter_flow/flutter_flow_icon_button.dart';
import 'package:hub/flutter_flow/flutter_flow_theme.dart';
import 'package:hub/flutter_flow/flutter_flow_util.dart';
import 'package:hub/flutter_flow/nav/nav.dart';
import 'package:hub/pages/preferences_settings_page/preferences_settings_model.dart';
import 'package:hub/shared/utils/limited_text_size.dart';
import 'package:material_symbols_icons/symbols.dart';
import 'package:provider/provider.dart';
class PreferencesPageWidget extends StatefulWidget {
@ -41,6 +38,7 @@ class _PreferencesPageWidgetState extends State<PreferencesPageWidget> {
automaticallyImplyLeading: false,
forceMaterialTransparency: true,
leading: FlutterFlowIconButton(
key: ValueKey<String>('BackNavigationAppBar'),
borderColor: Colors.transparent,
borderRadius: 30.0,
borderWidth: 1.0,

View File

@ -36,6 +36,7 @@ class _ProvisionalScheduleState extends State<ProvisionalSchedule> {
automaticallyImplyLeading: false,
forceMaterialTransparency: true,
leading: FlutterFlowIconButton(
key: ValueKey<String>('BackNavigationAppBar'),
borderColor: Colors.transparent,
borderRadius: 30.0,
borderWidth: 1.0,

View File

@ -18,12 +18,9 @@ import 'package:hub/flutter_flow/flutter_flow_util.dart';
import 'package:hub/flutter_flow/flutter_flow_widgets.dart';
import 'package:hub/flutter_flow/nav/nav.dart';
import 'package:hub/pages/qr_code_page/qr_code_page_model.dart';
import 'package:hub/shared/utils/biometric_util.dart';
import 'package:hub/shared/utils/limited_text_size.dart';
import 'package:percent_indicator/circular_percent_indicator.dart';
import 'package:qr_flutter/qr_flutter.dart';
class QrCodePageWidget extends StatefulWidget {
@ -475,6 +472,7 @@ class _QrCodePageWidgetState extends State<QrCodePageWidget>
AppBar buildAppBar(BuildContext context) {
return AppBar(
key: ValueKey<String>('BackNavigationAppBar'),
backgroundColor: FlutterFlowTheme.of(context).primaryBackground,
automaticallyImplyLeading: false,
leading: FlutterFlowIconButton(
@ -492,7 +490,10 @@ class _QrCodePageWidgetState extends State<QrCodePageWidget>
},
),
title: Text(
FFLocalizations.of(context).getText('ku7jqe53'),
FFLocalizations.of(context).getVariableText(
ptText: 'QRCode de Acesso',
enText: 'Access QRCode',
),
style: FlutterFlowTheme.of(context).headlineMedium.override(
fontFamily: FlutterFlowTheme.of(context).headlineMediumFamily,
color: FlutterFlowTheme.of(context).primaryText,

View File

@ -43,6 +43,7 @@ class _RegisterVisitorPageWidgetState extends State<RegisterVisitorPageWidget> {
backgroundColor: FlutterFlowTheme.of(context).primaryBackground,
automaticallyImplyLeading: false,
leading: FlutterFlowIconButton(
key: ValueKey<String>('BackNavigationAppBar'),
borderColor: Colors.transparent,
borderRadius: 30.0,
borderWidth: 1.0,
@ -57,8 +58,9 @@ class _RegisterVisitorPageWidgetState extends State<RegisterVisitorPageWidget> {
},
),
title: Text(
FFLocalizations.of(context).getText(
'megskb6s' /* Cadastrar Visitante */,
FFLocalizations.of(context).getVariableText(
ptText: 'Cadastrar Visitantes',
enText: 'Register Visitors',
),
style: FlutterFlowTheme.of(context).headlineMedium.override(
fontFamily: FlutterFlowTheme.of(context).headlineMediumFamily,

View File

@ -157,6 +157,7 @@ class _ResidentsOnThePropertyState extends State<ResidentsOnTheProperty>
Widget _backButton(BuildContext context, FlutterFlowTheme theme) {
return FlutterFlowIconButton(
key: ValueKey<String>('BackNavigationAppBar'),
borderColor: Colors.transparent,
borderRadius: 30.0,
borderWidth: 1.0,

View File

@ -126,6 +126,7 @@ class _ScheduleCompleteVisitPageWidgetState
forceMaterialTransparency: true,
elevation: 0.0,
leading: FlutterFlowIconButton(
key: ValueKey<String>('BackNavigationAppBar'),
borderColor: Colors.transparent,
borderRadius: 30.0,
borderWidth: 1.0,

View File

@ -152,6 +152,7 @@ class _VehicleOnThePropertyState extends State<VehicleOnTheProperty>
Widget _backButton(BuildContext context, FlutterFlowTheme theme) {
return FlutterFlowIconButton(
key: ValueKey<String>('BackNavigationAppBar'),
borderColor: Colors.transparent,
borderRadius: 30.0,
borderWidth: 1.0,

View File

@ -7,8 +7,8 @@ import 'package:hub/flutter_flow/flutter_flow_theme.dart';
import 'package:hub/flutter_flow/flutter_flow_util.dart';
import 'package:hub/pages/visits_on_the_property/model.dart';
import 'package:hub/shared/utils/dialog_util.dart';
import 'package:hub/shared/utils/log_util.dart';
import 'package:hub/shared/utils/limited_text_size.dart';
import 'package:hub/shared/utils/log_util.dart';
class VisitsOnTheProperty extends StatefulWidget {
const VisitsOnTheProperty({super.key});
@ -135,7 +135,9 @@ class _VisitsOnThePropertyState extends State<VisitsOnTheProperty>
automaticallyImplyLeading: false,
title: Text(
FFLocalizations.of(context).getVariableText(
ptText: 'Visitas em aberto', enText: 'Opened visits'),
ptText: 'Visitas Abertas',
enText: 'Opened Visits',
),
style: FlutterFlowTheme.of(context).headlineMedium.override(
fontFamily: FlutterFlowTheme.of(context).headlineMediumFamily,
color: FlutterFlowTheme.of(context).primaryText,
@ -155,6 +157,7 @@ class _VisitsOnThePropertyState extends State<VisitsOnTheProperty>
Widget _backButton(BuildContext context, FlutterFlowTheme theme) {
return FlutterFlowIconButton(
key: ValueKey<String>('BackNavigationAppBar'),
borderColor: Colors.transparent,
borderRadius: 30.0,
borderWidth: 1.0,

View File

@ -1,9 +1,9 @@
import '/components/templates_components/welcome_template_component/welcome_template_component_widget.dart';
import '/flutter_flow/flutter_flow_util.dart';
import 'welcome_page_widget.dart' show WelcomePageWidget;
import 'welcome_page_widget.dart' show WelcomePage;
import 'package:flutter/material.dart';
class WelcomePageModel extends FlutterFlowModel<WelcomePageWidget> {
class WelcomePageModel extends FlutterFlowModel<WelcomePage> {
/// Local state fields for this page.
String toggleIdx = 'welcome';

View File

@ -11,14 +11,14 @@ import 'welcome_page_model.dart';
export 'welcome_page_model.dart';
class WelcomePageWidget extends StatefulWidget with Switcher {
const WelcomePageWidget({super.key});
class WelcomePage extends StatefulWidget with Switcher {
const WelcomePage({super.key});
@override
State<WelcomePageWidget> createState() => _WelcomePageWidgetState();
State<WelcomePage> createState() => _WelcomePageState();
}
class _WelcomePageWidgetState extends State<WelcomePageWidget> {
class _WelcomePageState extends State<WelcomePage> {
late WelcomePageModel _model;
final scaffoldKey = GlobalKey<ScaffoldState>();

View File

@ -8,6 +8,7 @@ export 'log_util.dart';
export 'path_util.dart';
export 'share_util.dart';
export 'snackbar_util.dart';
export 'string_util.dart';
export 'text_util.dart';
export 'validator_util.dart';
export 'webview_util.dart';

View File

@ -0,0 +1,7 @@
import 'dart:io';
class TestUtil {
static bool get isInTest {
return Platform.environment.containsKey('FLUTTER_TEST');
}
}

View File

@ -34,10 +34,10 @@ packages:
dependency: "direct main"
description:
name: app_links
sha256: ad1a6d598e7e39b46a34f746f9a8b011ee147e4c275d407fa457e7a62f84dd99
sha256: "433df2e61b10519407475d7f69e470789d23d593f28224c38ba1068597be7950"
url: "https://pub.dev"
source: hosted
version: "6.3.2"
version: "6.3.3"
app_links_linux:
dependency: transitive
description:
@ -66,18 +66,18 @@ packages:
dependency: "direct main"
description:
name: app_tracking_transparency
sha256: "64d9745931e565790abdea91b518ac8dc3cebe6d0d0aaf7119343271b983259a"
sha256: "1f71f4d8402552fbf8b191d4edab301f233c1af794878b7bc56c708470ffd74c"
url: "https://pub.dev"
source: hosted
version: "2.0.6"
version: "2.0.6+1"
archive:
dependency: transitive
description:
name: archive
sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d
sha256: "6199c74e3db4fbfbd04f66d739e72fe11c8a8957d5f219f1f4482dbde6420b5a"
url: "https://pub.dev"
source: hosted
version: "3.6.1"
version: "4.0.2"
args:
dependency: transitive
description:
@ -130,10 +130,10 @@ packages:
dependency: transitive
description:
name: bloc
sha256: "106842ad6569f0b60297619e9e0b1885c2fb9bf84812935490e6c5275777804e"
sha256: "52c10575f4445c61dd9e0cafcc6356fdd827c4c64dd7945ef3c4105f6b6ac189"
url: "https://pub.dev"
source: hosted
version: "8.1.4"
version: "9.0.0"
boolean_selector:
dependency: transitive
description:
@ -146,50 +146,50 @@ packages:
dependency: transitive
description:
name: build
sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0"
sha256: cef23f1eda9b57566c81e2133d196f8e3df48f244b317368d65c5943d91148f0
url: "https://pub.dev"
source: hosted
version: "2.4.1"
version: "2.4.2"
build_config:
dependency: transitive
description:
name: build_config
sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1
sha256: "4ae2de3e1e67ea270081eaee972e1bd8f027d459f249e0f1186730784c2e7e33"
url: "https://pub.dev"
source: hosted
version: "1.1.1"
version: "1.1.2"
build_daemon:
dependency: transitive
description:
name: build_daemon
sha256: "79b2aef6ac2ed00046867ed354c88778c9c0f029df8a20fe10b5436826721ef9"
sha256: "294a2edaf4814a378725bfe6358210196f5ea37af89ecd81bfa32960113d4948"
url: "https://pub.dev"
source: hosted
version: "4.0.2"
version: "4.0.3"
build_resolvers:
dependency: transitive
description:
name: build_resolvers
sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a"
sha256: "99d3980049739a985cf9b21f30881f46db3ebc62c5b8d5e60e27440876b1ba1e"
url: "https://pub.dev"
source: hosted
version: "2.4.2"
version: "2.4.3"
build_runner:
dependency: "direct dev"
description:
name: build_runner
sha256: "028819cfb90051c6b5440c7e574d1896f8037e3c96cf17aaeb054c9311cfbf4d"
sha256: "74691599a5bc750dc96a6b4bfd48f7d9d66453eab04c7f4063134800d6a5c573"
url: "https://pub.dev"
source: hosted
version: "2.4.13"
version: "2.4.14"
build_runner_core:
dependency: transitive
description:
name: build_runner_core
sha256: f8126682b87a7282a339b871298cc12009cb67109cfa1614d6436fb0289193e0
sha256: "22e3aa1c80e0ada3722fe5b63fd43d9c8990759d0a2cf489c8c5d7b2bdebc021"
url: "https://pub.dev"
source: hosted
version: "7.3.2"
version: "8.0.0"
built_collection:
dependency: transitive
description:
@ -202,10 +202,10 @@ packages:
dependency: transitive
description:
name: built_value
sha256: c7913a9737ee4007efedaffc968c049fd0f3d0e49109e778edc10de9426005cb
sha256: "28a712df2576b63c6c005c465989a348604960c0958d28be5303ba9baa841ac2"
url: "https://pub.dev"
source: hosted
version: "8.9.2"
version: "8.9.3"
cached_network_image:
dependency: "direct main"
description:
@ -286,6 +286,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.1.2"
coverage:
dependency: transitive
description:
name: coverage
sha256: e3493833ea012784c740e341952298f1cc77f1f01b1bbc3eb4eecf6984fb7f43
url: "https://pub.dev"
source: hosted
version: "1.11.1"
cross_file:
dependency: transitive
description:
@ -338,10 +346,18 @@ packages:
dependency: transitive
description:
name: device_info_plus_platform_interface
sha256: "282d3cf731045a2feb66abfe61bbc40870ae50a3ed10a4d3d217556c35c8c2ba"
sha256: "0b04e02b30791224b31969eb1b50d723498f402971bff3630bca2ba839bd1ed2"
url: "https://pub.dev"
source: hosted
version: "7.0.1"
version: "7.0.2"
dispose_scope:
dependency: transitive
description:
name: dispose_scope
sha256: "48ec38ca2631c53c4f8fa96b294c801e55c335db5e3fb9f82cede150cfe5a2af"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
dropdown_button2:
dependency: "direct main"
description:
@ -466,10 +482,10 @@ packages:
dependency: transitive
description:
name: firebase_core_platform_interface
sha256: b94b217e3ad745e784960603d33d99471621ecca151c99c670869b76e50ad2a6
sha256: d7253d255ff10f85cfd2adaba9ac17bae878fa3ba577462451163bd9f1d1f0bf
url: "https://pub.dev"
source: hosted
version: "5.3.1"
version: "5.4.0"
firebase_core_web:
dependency: transitive
description:
@ -543,10 +559,10 @@ packages:
dependency: "direct main"
description:
name: flutter_bloc
sha256: b594505eac31a0518bdcb4b5b79573b8d9117b193cc80cc12e17d639b10aa27a
sha256: "153856bdaac302bbdc58a1d1403d50c40557254aa05eaeed40515d88a25a526b"
url: "https://pub.dev"
source: hosted
version: "8.1.6"
version: "9.0.0"
flutter_cache_manager:
dependency: transitive
description:
@ -641,10 +657,10 @@ packages:
dependency: transitive
description:
name: flutter_plugin_android_lifecycle
sha256: "9b78450b89f059e96c9ebb355fa6b3df1d6b330436e0b885fb49594c41721398"
sha256: "615a505aef59b151b46bbeef55b36ce2b6ed299d160c51d84281946f0aa0ce0e"
url: "https://pub.dev"
source: hosted
version: "2.0.23"
version: "2.0.24"
flutter_riverpod:
dependency: "direct main"
description:
@ -657,50 +673,58 @@ packages:
dependency: "direct main"
description:
name: flutter_secure_storage
sha256: "165164745e6afb5c0e3e3fcc72a012fb9e58496fb26ffb92cf22e16a821e85d0"
sha256: f7eceb0bc6f4fd0441e29d43cab9ac2a1c5ffd7ea7b64075136b718c46954874
url: "https://pub.dev"
source: hosted
version: "9.2.2"
version: "10.0.0-beta.4"
flutter_secure_storage_darwin:
dependency: transitive
description:
name: flutter_secure_storage_darwin
sha256: f226f2a572bed96bc6542198ebaec227150786e34311d455a7e2d3d06d951845
url: "https://pub.dev"
source: hosted
version: "0.1.0"
flutter_secure_storage_linux:
dependency: "direct main"
description:
name: flutter_secure_storage_linux
sha256: "4d91bfc23047422cbcd73ac684bc169859ee766482517c22172c86596bf1464b"
sha256: "9b4b73127e857cd3117d43a70fa3dddadb6e0b253be62e6a6ab85caa0742182c"
url: "https://pub.dev"
source: hosted
version: "1.2.1"
version: "2.0.1"
flutter_secure_storage_macos:
dependency: "direct main"
description:
name: flutter_secure_storage_macos
sha256: "1693ab11121a5f925bbea0be725abfcfbbcf36c1e29e571f84a0c0f436147a81"
sha256: "75894eb6b402ac7f7f5ee5487d651b87855a338e26eb6993f4b2fce33013a615"
url: "https://pub.dev"
source: hosted
version: "3.1.2"
version: "4.0.0"
flutter_secure_storage_platform_interface:
dependency: "direct main"
description:
name: flutter_secure_storage_platform_interface
sha256: cf91ad32ce5adef6fba4d736a542baca9daf3beac4db2d04be350b87f69ac4a8
sha256: "8ceea1223bee3c6ac1a22dabd8feefc550e4729b3675de4b5900f55afcb435d6"
url: "https://pub.dev"
source: hosted
version: "1.1.2"
version: "2.0.1"
flutter_secure_storage_web:
dependency: "direct main"
description:
name: flutter_secure_storage_web
sha256: f4ebff989b4f07b2656fb16b47852c0aab9fed9b4ec1c70103368337bc1886a9
sha256: "4c3f233e739545c6cb09286eeec1cc4744138372b985113acc904f7263bef517"
url: "https://pub.dev"
source: hosted
version: "1.2.1"
version: "2.0.0"
flutter_secure_storage_windows:
dependency: "direct main"
description:
name: flutter_secure_storage_windows
sha256: b20b07cb5ed4ed74fc567b78a72936203f587eba460af1df11281c9326cd3709
sha256: ff32af20f70a8d0e59b2938fc92de35b54a74671041c814275afd80e27df9f21
url: "https://pub.dev"
source: hosted
version: "3.1.2"
version: "4.0.0"
flutter_shaders:
dependency: transitive
description:
@ -729,10 +753,10 @@ packages:
dependency: "direct main"
description:
name: flutter_svg
sha256: "54900a1a1243f3c4a5506d853a2b5c2dbc38d5f27e52a52618a8054401431123"
sha256: c200fd79c918a40c5cd50ea0877fa13f81bdaf6f0a5d3dbcc2a13e3285d6aa1b
url: "https://pub.dev"
source: hosted
version: "2.0.16"
version: "2.0.17"
flutter_test:
dependency: "direct dev"
description: flutter
@ -808,10 +832,10 @@ packages:
dependency: "direct main"
description:
name: go_router
sha256: "2fd11229f59e23e967b0775df8d5948a519cd7e1e8b6e849729e010587b46539"
sha256: "7c2d40b59890a929824f30d442e810116caf5088482629c894b9e4478c67472d"
url: "https://pub.dev"
source: hosted
version: "14.6.2"
version: "14.6.3"
google_fonts:
dependency: "direct main"
description:
@ -864,26 +888,26 @@ packages:
dependency: transitive
description:
name: http_multi_server
sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b"
sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8
url: "https://pub.dev"
source: hosted
version: "3.2.1"
version: "3.2.2"
http_parser:
dependency: transitive
description:
name: http_parser
sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571"
url: "https://pub.dev"
source: hosted
version: "4.0.2"
version: "4.1.2"
image:
dependency: "direct dev"
description:
name: image
sha256: f31d52537dc417fdcde36088fdf11d191026fd5e4fae742491ebd40e5a8bea7d
sha256: "8346ad4b5173924b5ddddab782fc7d8a6300178c8b1dc427775405a01701c4a6"
url: "https://pub.dev"
source: hosted
version: "4.3.0"
version: "4.5.2"
image_picker:
dependency: "direct main"
description:
@ -896,10 +920,10 @@ packages:
dependency: "direct main"
description:
name: image_picker_android
sha256: fa8141602fde3f7e2f81dbf043613eb44dfa325fa0bcf93c0f142c9f7a2c193e
sha256: b62d34a506e12bb965e824b6db4fbf709ee4589cf5d3e99b45ab2287b008ee0c
url: "https://pub.dev"
source: hosted
version: "0.8.12+18"
version: "0.8.12+20"
image_picker_for_web:
dependency: "direct main"
description:
@ -912,10 +936,10 @@ packages:
dependency: "direct main"
description:
name: image_picker_ios
sha256: "4f0568120c6fcc0aaa04511cb9f9f4d29fc3d0139884b1d06be88dcec7641d6b"
sha256: "05da758e67bc7839e886b3959848aa6b44ff123ab4b28f67891008afe8ef9100"
url: "https://pub.dev"
source: hosted
version: "0.8.12+1"
version: "0.8.12+2"
image_picker_linux:
dependency: transitive
description:
@ -936,10 +960,10 @@ packages:
dependency: "direct main"
description:
name: image_picker_platform_interface
sha256: "9ec26d410ff46f483c5519c29c02ef0e02e13a543f882b152d4bfd2f06802f80"
sha256: "886d57f0be73c4b140004e78b9f28a8914a09e50c2d816bdd0520051a71236a0"
url: "https://pub.dev"
source: hosted
version: "2.10.0"
version: "2.10.1"
image_picker_windows:
dependency: transitive
description:
@ -1037,10 +1061,10 @@ packages:
dependency: "direct dev"
description:
name: lints
sha256: "3315600f3fb3b135be672bf4a178c55f274bebe368325ae18462c89ac1e3b413"
sha256: c35bb79562d980e9a453fc715854e1ed39e24e7d0297a880ef54e17f9874a9d7
url: "https://pub.dev"
source: hosted
version: "5.0.0"
version: "5.1.1"
local_auth:
dependency: "direct main"
description:
@ -1061,10 +1085,10 @@ packages:
dependency: transitive
description:
name: local_auth_darwin
sha256: "6d2950da311d26d492a89aeb247c72b4653ddc93601ea36a84924a396806d49c"
sha256: "5c5127061107278ab4cafa1ac51b3b6760282bf1a2abf011270908a429d1634b"
url: "https://pub.dev"
source: hosted
version: "1.4.1"
version: "1.4.2"
local_auth_platform_interface:
dependency: transitive
description:
@ -1117,10 +1141,10 @@ packages:
dependency: "direct main"
description:
name: material_symbols_icons
sha256: "64404f47f8e0a9d20478468e5decef867a688660bad7173adcd20418d7f892c9"
sha256: "89aac72d25dd49303f71b3b1e70f8374791846729365b25bebc2a2531e5b86cd"
url: "https://pub.dev"
source: hosted
version: "4.2801.0"
version: "4.2801.1"
maybe_just_nothing:
dependency: transitive
description:
@ -1157,10 +1181,10 @@ packages:
dependency: "direct dev"
description:
name: mockito
sha256: "6841eed20a7befac0ce07df8116c8b8233ed1f4486a7647c7fc5a02ae6163917"
sha256: f99d8d072e249f719a5531735d146d8cf04c580d93920b04de75bef6dfb2daf6
url: "https://pub.dev"
source: hosted
version: "5.4.4"
version: "5.4.5"
nested:
dependency: transitive
description:
@ -1169,6 +1193,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.0"
node_preamble:
dependency: transitive
description:
name: node_preamble
sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db"
url: "https://pub.dev"
source: hosted
version: "2.0.2"
octo_image:
dependency: transitive
description:
@ -1189,26 +1221,26 @@ packages:
dependency: "direct main"
description:
name: package_info_plus
sha256: da8d9ac8c4b1df253d1a328b7bf01ae77ef132833479ab40763334db13b91cce
sha256: "739e0a5c3c4055152520fa321d0645ee98e932718b4c8efeeb51451968fe0790"
url: "https://pub.dev"
source: hosted
version: "8.1.1"
version: "8.1.3"
package_info_plus_platform_interface:
dependency: transitive
description:
name: package_info_plus_platform_interface
sha256: ac1f4a4847f1ade8e6a87d1f39f5d7c67490738642e2542f559ec38c37489a66
sha256: a5ef9986efc7bf772f2696183a3992615baa76c1ffb1189318dd8803778fb05b
url: "https://pub.dev"
source: hosted
version: "3.0.1"
version: "3.0.2"
page_transition:
dependency: "direct main"
description:
name: page_transition
sha256: dee976b1f23de9bbef5cd512fe567e9f6278caee11f5eaca9a2115c19dc49ef6
sha256: "9d2a780d7d68b53ae82fbcc43e06a16195e6775e9aae40e55dc0cbb593460f9d"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
version: "2.2.1"
path:
dependency: transitive
description:
@ -1273,6 +1305,30 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.3.0"
patrol:
dependency: "direct dev"
description:
name: patrol
sha256: f2b423122e63b1251fc31165ba1f7d85d60e22b4d20076ef39dcb47f83e35467
url: "https://pub.dev"
source: hosted
version: "3.13.2"
patrol_finders:
dependency: "direct dev"
description:
name: patrol_finders
sha256: "5a1e2b4c6636e89645fc596d68224cfe6cca28e11c855b98dd0df9bed0d80405"
url: "https://pub.dev"
source: hosted
version: "2.6.0"
patrol_log:
dependency: transitive
description:
name: patrol_log
sha256: ad5d7b759d16071ca16aa9b27eb4f106ce23079792d4312941874dbc33e795cb
url: "https://pub.dev"
source: hosted
version: "0.2.2"
percent_indicator:
dependency: "direct main"
description:
@ -1369,6 +1425,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.5.1"
posix:
dependency: transitive
description:
name: posix
sha256: a0117dc2167805aa9125b82eee515cc891819bac2f538c83646d355b16f58b9a
url: "https://pub.dev"
source: hosted
version: "6.0.1"
process:
dependency: transitive
description:
@ -1397,10 +1461,10 @@ packages:
dependency: transitive
description:
name: pubspec_parse
sha256: c799b721d79eb6ee6fa56f00c04b472dcd44a30d258fac2174a6ec57302678f8
sha256: "0560ba233314abbed0a48a2956f7f022cce7c3e1e73df540277da7544cad4082"
url: "https://pub.dev"
source: hosted
version: "1.3.0"
version: "1.5.0"
qr:
dependency: transitive
description:
@ -1461,34 +1525,34 @@ packages:
dependency: transitive
description:
name: share_plus_platform_interface
sha256: c57c0bbfec7142e3a0f55633be504b796af72e60e3c791b44d5a017b985f7a48
sha256: cc012a23fc2d479854e6c80150696c4a5f5bb62cb89af4de1c505cf78d0a5d0b
url: "https://pub.dev"
source: hosted
version: "5.0.1"
version: "5.0.2"
shared_preferences:
dependency: "direct main"
description:
name: shared_preferences
sha256: "95f9997ca1fb9799d494d0cb2a780fd7be075818d59f00c43832ed112b158a82"
sha256: a752ce92ea7540fc35a0d19722816e04d0e72828a4200e83a98cf1a1eb524c9a
url: "https://pub.dev"
source: hosted
version: "2.3.3"
version: "2.3.5"
shared_preferences_android:
dependency: "direct main"
description:
name: shared_preferences_android
sha256: "7f172d1b06de5da47b6264c2692ee2ead20bbbc246690427cdb4fc301cd0c549"
sha256: bf808be89fe9dc467475e982c1db6c2faf3d2acf54d526cd5ec37d86c99dbd84
url: "https://pub.dev"
source: hosted
version: "2.3.4"
version: "2.4.1"
shared_preferences_foundation:
dependency: "direct main"
description:
name: shared_preferences_foundation
sha256: "07e050c7cd39bad516f8d64c455f04508d09df104be326d8c02551590a0d513d"
sha256: "6a52cfcdaeac77cad8c97b539ff688ccfc458c007b4db12be584fbe5c0e49e03"
url: "https://pub.dev"
source: hosted
version: "2.5.3"
version: "2.5.4"
shared_preferences_linux:
dependency: transitive
description:
@ -1525,10 +1589,26 @@ packages:
dependency: transitive
description:
name: shelf
sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4
sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12
url: "https://pub.dev"
source: hosted
version: "1.4.1"
version: "1.4.2"
shelf_packages_handler:
dependency: transitive
description:
name: shelf_packages_handler
sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e"
url: "https://pub.dev"
source: hosted
version: "3.0.2"
shelf_static:
dependency: transitive
description:
name: shelf_static
sha256: c87c3875f91262785dade62d135760c2c69cb217ac759485334c5857ad89f6e3
url: "https://pub.dev"
source: hosted
version: "1.1.3"
shelf_web_socket:
dependency: transitive
description:
@ -1554,10 +1634,26 @@ packages:
dependency: transitive
description:
name: source_helper
sha256: "6adebc0006c37dd63fe05bca0a929b99f06402fc95aa35bf36d67f5c06de01fd"
sha256: "86d247119aedce8e63f4751bd9626fc9613255935558447569ad42f9f5b48b3c"
url: "https://pub.dev"
source: hosted
version: "1.3.4"
version: "1.3.5"
source_map_stack_trace:
dependency: transitive
description:
name: source_map_stack_trace
sha256: c0713a43e323c3302c2abe2a1cc89aa057a387101ebd280371d6a6c9fa68516b
url: "https://pub.dev"
source: hosted
version: "2.1.2"
source_maps:
dependency: transitive
description:
name: source_maps
sha256: "190222579a448b03896e0ca6eca5998fa810fda630c1d65e2f78b3f638f54812"
url: "https://pub.dev"
source: hosted
version: "0.10.13"
source_span:
dependency: transitive
description:
@ -1602,10 +1698,10 @@ packages:
dependency: transitive
description:
name: sqflite_darwin
sha256: "96a698e2bc82bd770a4d6aab00b42396a7c63d9e33513a56945cbccb594c2474"
sha256: "22adfd9a2c7d634041e96d6241e6e1c8138ca6817018afc5d443fef91dcefa9c"
url: "https://pub.dev"
source: hosted
version: "2.4.1"
version: "2.4.1+1"
sqflite_platform_interface:
dependency: transitive
description:
@ -1642,10 +1738,10 @@ packages:
dependency: transitive
description:
name: stream_transform
sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f"
sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871
url: "https://pub.dev"
source: hosted
version: "2.1.0"
version: "2.1.1"
string_scanner:
dependency: transitive
description:
@ -1678,6 +1774,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.2.1"
test:
dependency: "direct dev"
description:
name: test
sha256: "713a8789d62f3233c46b4a90b174737b2c04cb6ae4500f2aa8b1be8f03f5e67f"
url: "https://pub.dev"
source: hosted
version: "1.25.8"
test_api:
dependency: transitive
description:
@ -1686,6 +1790,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.7.3"
test_core:
dependency: transitive
description:
name: test_core
sha256: "12391302411737c176b0b5d6491f466b0dd56d4763e347b6714efbaa74d7953d"
url: "https://pub.dev"
source: hosted
version: "0.6.5"
timeago:
dependency: "direct main"
description:
@ -1698,10 +1810,10 @@ packages:
dependency: transitive
description:
name: timing
sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32"
sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe"
url: "https://pub.dev"
source: hosted
version: "1.0.1"
version: "1.0.2"
typed_data:
dependency: transitive
description:
@ -1762,18 +1874,18 @@ packages:
dependency: transitive
description:
name: url_launcher_web
sha256: "772638d3b34c779ede05ba3d38af34657a05ac55b06279ea6edd409e323dca8e"
sha256: "3ba963161bd0fe395917ba881d320b9c4f6dd3c4a233da62ab18a5025c85f1e9"
url: "https://pub.dev"
source: hosted
version: "2.3.3"
version: "2.4.0"
url_launcher_windows:
dependency: transitive
description:
name: url_launcher_windows
sha256: "44cf3aabcedde30f2dba119a9dea3b0f2672fbe6fa96e85536251d678216b3c4"
sha256: "3284b6d2ac454cf34f114e1d3319866fdd1e19cdc329999057e44ffe936cfa77"
url: "https://pub.dev"
source: hosted
version: "3.1.3"
version: "3.1.4"
uuid:
dependency: "direct overridden"
description:
@ -1794,10 +1906,10 @@ packages:
dependency: transitive
description:
name: vector_graphics_codec
sha256: "2430b973a4ca3c4dbc9999b62b8c719a160100dcbae5c819bae0cacce32c9cdb"
sha256: "99fd9fbd34d9f9a32efd7b6a6aae14125d8237b10403b422a6a6dfeac2806146"
url: "https://pub.dev"
source: hosted
version: "1.1.12"
version: "1.1.13"
vector_graphics_compiler:
dependency: transitive
description:
@ -1826,10 +1938,10 @@ packages:
dependency: transitive
description:
name: watcher
sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8"
sha256: "69da27e49efa56a15f8afe8f4438c4ec02eff0a117df1b22ea4aad194fe1c104"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
version: "1.1.1"
web:
dependency: transitive
description:
@ -1862,6 +1974,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.0.4"
webkit_inspection_protocol:
dependency: transitive
description:
name: webkit_inspection_protocol
sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572"
url: "https://pub.dev"
source: hosted
version: "1.2.1"
webview_flutter:
dependency: "direct main"
description:
@ -1874,10 +1994,10 @@ packages:
dependency: transitive
description:
name: webview_flutter_android
sha256: "285cedfd9441267f6cca8843458620b5fda1af75b04f5818d0441acda5d7df19"
sha256: d1ee28f44894cbabb1d94cc42f9980297f689ff844d067ec50ff88d86e27d63f
url: "https://pub.dev"
source: hosted
version: "4.1.0"
version: "4.3.0"
webview_flutter_platform_interface:
dependency: transitive
description:
@ -1890,10 +2010,10 @@ packages:
dependency: transitive
description:
name: webview_flutter_wkwebview
sha256: b7e92f129482460951d96ef9a46b49db34bd2e1621685de26e9eaafd9674e7eb
sha256: "4adc14ea9a770cc9e2c8f1ac734536bd40e82615bd0fa6b94be10982de656cc7"
url: "https://pub.dev"
source: hosted
version: "3.16.3"
version: "3.17.0"
win32:
dependency: "direct overridden"
description:
@ -1930,10 +2050,10 @@ packages:
dependency: transitive
description:
name: yaml
sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5"
sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce
url: "https://pub.dev"
source: hosted
version: "3.1.2"
version: "3.1.3"
sdks:
dart: ">=3.5.0 <4.0.0"
flutter: ">=3.24.0"
dart: ">=3.6.0 <4.0.0"
flutter: ">=3.27.0"

View File

@ -37,12 +37,12 @@ dependencies:
# flutter_plugin_android_lifecycle: ^2.0.23
share_plus: ^10.0.0
# connectivity_plus: ^6.0.5
flutter_secure_storage: 9.2.2
flutter_secure_storage_linux: 1.2.1
flutter_secure_storage_macos: 3.1.2
flutter_secure_storage_platform_interface: 1.1.2
flutter_secure_storage_web: 1.2.1
flutter_secure_storage_windows: 3.1.2
flutter_secure_storage: ^10.0.0-beta.2
flutter_secure_storage_linux: ^2.0.0
flutter_secure_storage_macos: ^4.0.0
flutter_secure_storage_platform_interface: ^2.0.1
flutter_secure_storage_web: ^2.0.0
flutter_secure_storage_windows: ^4.0.0
flutter_spinkit: 5.2.1
flutter_staggered_grid_view: 0.7.0
flutter_svg: ^2.0.15
@ -56,13 +56,13 @@ dependencies:
image_picker_for_web: ^3.0.5
persistent_bottom_nav_bar: ^6.2.1
image_picker_ios: ^0.8.12+1
image_picker_platform_interface: 2.10.0
image_picker_platform_interface: ^2.10.1
local_auth: ^2.2.0
intl: ^0.19.0
# camera: ^0.11.0+2
json_path: ^0.7.4
mime_type: ^1.0.1
page_transition: 2.1.0
page_transition: ^2.2.1
path_provider: ^2.1.4
path_provider_android: ^2.2.12
google_mlkit_face_detection: ^0.12.0
@ -92,7 +92,7 @@ dependencies:
material_symbols_icons: ^4.2784.0
fluttertoast: ^8.2.8
cupertino_icons: ^1.0.0
flutter_bloc: ^8.1.6
flutter_bloc: ^9.0.0
flutter_riverpod: ^2.5.1
qr_flutter: ^4.1.0
permission_handler: ^11.3.1
@ -124,6 +124,9 @@ dev_dependencies:
build_runner: ^2.4.13
freezed: ^2.5.7
json_serializable: ^6.9.0
test: ^1.25.8
patrol: ^3.13.2
patrol_finders: ^2.6.0
flutter_launcher_icons:
android: "launcher_icon"
@ -157,3 +160,10 @@ fonts:
- family: Menu
fonts:
- asset: assets/fonts/menu.ttf
patrol:
app_name: FRE ACCESS HUB
android:
package_name: com.freaccess.hub
ios:
bundle_id: br.com.freaccess.hub

View File

@ -0,0 +1,11 @@
# Ativa o 'patrol_cli' globalmente
flutter pub global activate patrol_cli
# Limpa os builds anteriores do Flutter
flutter clean
# Obtém as dependências do Flutter
flutter pub get
# Verifica a configuração do Patrol
patrol doctor

View File

@ -0,0 +1,70 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:hub/features/backend/index.dart';
import 'package:hub/features/menu/index.dart';
import 'package:hub/features/module/index.dart';
import 'package:hub/features/storage/index.dart';
import 'package:hub/initialization.dart';
import 'package:integration_test/integration_test.dart';
class ApiImpl implements Api {
@override
var getLicense = LicenseApi() as GetLicense;
}
class LicenseApi extends GetLicense {
@override
Future<ApiCallResponse> call() async => ApiCallResponse(
{
'error_msg': 'error',
},
{
'Content-Type': 'application/x-www-form-urlencoded',
},
200,
);
}
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
setUpAll(() async {
await initializeApp();
});
group('Test', () {
late LicenseRepository repo = LicenseRepositoryImpl(
DatabaseService.database,
ApiImpl(),
);
List<MenuEntry> menuEntries = MenuEntry.entries;
test('update license', () async {
late bool result;
result = await repo.updateLicense();
expect(result, true);
});
test('get module', () async {
late String? result;
for (var entry in menuEntries) {
result = await repo.getModule(entry.key);
expect(result, isNotNull);
}
});
test('set module', () async {
late bool? result;
for (var entry in menuEntries) {
result = await repo.setModule(entry.key, '');
expect(result, true);
}
});
test('clean license', () async {
late bool result;
result = await repo.cleanLicense();
expect(result, true);
});
});
}