Compare commits
No commits in common. "fb5f755d7089cf8a1b58afe5a73ec71294364cac" and "10bf8f523c94c4ca79940738545cdb91db1d8e9f" have entirely different histories.
fb5f755d70
...
10bf8f523c
|
@ -1 +1 @@
|
||||||
gradle 8.10.2
|
gradle 7.6.1
|
||||||
|
|
|
@ -7,11 +7,9 @@ import 'package:firebase_crashlytics/firebase_crashlytics.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:hub/components/atomic_components/shared_components_atoms/submit_button.dart';
|
|
||||||
import 'package:hub/components/molecular_components/throw_exception/throw_exception_widget.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/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/components/templates_components/card_item_template_component/card_item_template_component_widget.dart';
|
||||||
import 'package:hub/components/templates_components/details_component/details_component_widget.dart';
|
|
||||||
import 'package:hub/features/backend/api_requests/index.dart';
|
import 'package:hub/features/backend/api_requests/index.dart';
|
||||||
import 'package:hub/features/local/index.dart';
|
import 'package:hub/features/local/index.dart';
|
||||||
import 'package:hub/features/menu/index.dart';
|
import 'package:hub/features/menu/index.dart';
|
||||||
|
@ -22,8 +20,6 @@ import 'package:hub/features/storage/index.dart';
|
||||||
import 'package:hub/flutter_flow/index.dart' as ff;
|
import 'package:hub/flutter_flow/index.dart' as ff;
|
||||||
import 'package:hub/flutter_flow/index.dart';
|
import 'package:hub/flutter_flow/index.dart';
|
||||||
import 'package:hub/main.dart';
|
import 'package:hub/main.dart';
|
||||||
import 'package:hub/pages/vehicles_on_the_property/vehicles_on_the_property.dart';
|
|
||||||
import 'package:integration_test/integration_test.dart';
|
|
||||||
import 'package:material_symbols_icons/symbols.dart';
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
import 'package:flutter_web_plugins/url_strategy.dart';
|
import 'package:flutter_web_plugins/url_strategy.dart';
|
||||||
|
|
||||||
|
@ -31,6 +27,7 @@ import 'app_test.dart';
|
||||||
import 'fuzzer/fuzzer.dart';
|
import 'fuzzer/fuzzer.dart';
|
||||||
|
|
||||||
import 'package:patrol_finders/patrol_finders.dart';
|
import 'package:patrol_finders/patrol_finders.dart';
|
||||||
|
import 'package:integration_test/integration_test.dart';
|
||||||
export 'package:flutter_test/flutter_test.dart';
|
export 'package:flutter_test/flutter_test.dart';
|
||||||
export 'package:patrol/patrol.dart';
|
export 'package:patrol/patrol.dart';
|
||||||
|
|
||||||
|
@ -59,7 +56,6 @@ part 'storage_test.dart';
|
||||||
part 'utils_test.dart';
|
part 'utils_test.dart';
|
||||||
|
|
||||||
part 'welcome_test.dart';
|
part 'welcome_test.dart';
|
||||||
part 'vehicle_test.dart';
|
|
||||||
|
|
||||||
late PatrolTester $;
|
late PatrolTester $;
|
||||||
|
|
||||||
|
@ -87,9 +83,5 @@ void main() {
|
||||||
|
|
||||||
LocalsTest.setLocal();
|
LocalsTest.setLocal();
|
||||||
LocalsTest.unlinkLocal();
|
LocalsTest.unlinkLocal();
|
||||||
|
LocalsTest.attachLocal();
|
||||||
VehicleTest.vehiclePage();
|
|
||||||
VehicleTest.historyScreen();
|
|
||||||
VehicleTest.registerScreen();
|
|
||||||
VehicleTest.updateScreen();
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,320 +0,0 @@
|
||||||
part of 'app_test.dart';
|
|
||||||
|
|
||||||
class VehicleTest {
|
|
||||||
static Future<void> _initVehicleModule() async {
|
|
||||||
final vehicleParam = <String, dynamic>{
|
|
||||||
'display': 'VISIVEL',
|
|
||||||
'expirationDate': '',
|
|
||||||
'startDate': '',
|
|
||||||
'quantity': 0,
|
|
||||||
};
|
|
||||||
final vehicleManagerParam = <String, dynamic>{
|
|
||||||
'display': 'VISIVEL',
|
|
||||||
'expirationDate': '',
|
|
||||||
'startDate': '',
|
|
||||||
'quantity': 0,
|
|
||||||
};
|
|
||||||
await LicenseRepositoryImpl()
|
|
||||||
.setModule(LicenseKeys.vehicles.value, vehicleParam);
|
|
||||||
await LicenseRepositoryImpl()
|
|
||||||
.setModule(LicenseKeys.vehiclesManager.value, vehicleManagerParam);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Future<void> vehiclePage() async {
|
|
||||||
patrolWidgetTest(
|
|
||||||
'Vehicle Page',
|
|
||||||
(PatrolTester tester) async {
|
|
||||||
$ = tester;
|
|
||||||
$.tester.printToConsole('Vehicle Page');
|
|
||||||
final PatrolFinder throwsException = $(Dialog).$(ThrowExceptionWidget);
|
|
||||||
|
|
||||||
await _loggedWithMultiLocalsAccount();
|
|
||||||
await _initVehicleModule();
|
|
||||||
await $.pumpAndSettle();
|
|
||||||
await $.pumpWidgetAndSettle(const App());
|
|
||||||
|
|
||||||
ff.navigatorKey.currentContext!.go('/vehiclesOnThePropertyPage');
|
|
||||||
|
|
||||||
final String title = MenuEntry.entries //
|
|
||||||
.where((entry) => entry.key == 'FRE-HUB-VEHICLES') //
|
|
||||||
.map((entry) => entry.name)
|
|
||||||
.first;
|
|
||||||
|
|
||||||
final PatrolFinder appBar = await $(AppBar) //
|
|
||||||
.waitUntilExists();
|
|
||||||
final PatrolFinder titleAppBar = await appBar //
|
|
||||||
.$(title)
|
|
||||||
.waitUntilVisible();
|
|
||||||
expect(titleAppBar, findsOneWidget);
|
|
||||||
|
|
||||||
final PatrolFinder tab1 = await $(#TabView_Tab1) //
|
|
||||||
.waitUntilExists();
|
|
||||||
final PatrolFinder tab2 = await $(#TabView_Tab2) //
|
|
||||||
.waitUntilExists();
|
|
||||||
|
|
||||||
await tab2.tap();
|
|
||||||
await Future.delayed(const Duration(milliseconds: 500));
|
|
||||||
await tab1.tap();
|
|
||||||
|
|
||||||
final PatrolFinder listViewFinder = await $(VehicleHistoryScreen) //
|
|
||||||
.$(ListView)
|
|
||||||
.waitUntilVisible();
|
|
||||||
|
|
||||||
expect(listViewFinder, findsOneWidget);
|
|
||||||
|
|
||||||
final PatrolFinder entriesFinder = await $(listViewFinder)
|
|
||||||
.$(CardItemTemplateComponentWidget)
|
|
||||||
.waitUntilVisible();
|
|
||||||
|
|
||||||
expect(entriesFinder, findsWidgets);
|
|
||||||
final int entriesCount = entriesFinder.evaluate().length;
|
|
||||||
await $.pumpAndSettle();
|
|
||||||
|
|
||||||
if (entriesCount > 0)
|
|
||||||
for (int i = 0; i < entriesCount; i++) {
|
|
||||||
await $(entriesFinder.at(i)).scrollTo();
|
|
||||||
|
|
||||||
await $(entriesFinder.at(i))
|
|
||||||
.waitUntilVisible(timeout: const Duration(seconds: 1))
|
|
||||||
.tap(
|
|
||||||
settleTimeout: const Duration(seconds: 1),
|
|
||||||
settlePolicy: SettlePolicy.noSettle,
|
|
||||||
);
|
|
||||||
|
|
||||||
await $.pumpAndSettle(duration: Duration(milliseconds: 500));
|
|
||||||
final PatrolFinder detailsFinder =
|
|
||||||
await $(DetailsComponentWidget).waitUntilVisible();
|
|
||||||
expect(detailsFinder, findsOneWidget);
|
|
||||||
|
|
||||||
await _navigateBackUsingSystemGesture();
|
|
||||||
|
|
||||||
// await $.native.pressBack().then((_) => $.pumpAndSettle());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
patrolWidgetTest(
|
|
||||||
'License',
|
|
||||||
(PatrolTester tester) async {
|
|
||||||
$ = tester;
|
|
||||||
$.tester.printToConsole('Vehicle Page');
|
|
||||||
|
|
||||||
await _loggedWithMultiLocalsAccount();
|
|
||||||
await _initVehicleModule();
|
|
||||||
await $.pumpAndSettle();
|
|
||||||
|
|
||||||
await $.pumpWidgetAndSettle(const App());
|
|
||||||
|
|
||||||
ff.navigatorKey.currentContext!.go('/vehiclesOnThePropertyPage');
|
|
||||||
final String title = MenuEntry.entries //
|
|
||||||
.where((entry) => entry.key == 'FRE-HUB-VEHICLES') //
|
|
||||||
.map((entry) => entry.name)
|
|
||||||
.first;
|
|
||||||
|
|
||||||
final PatrolFinder appBar = await $(AppBar) //
|
|
||||||
.waitUntilExists();
|
|
||||||
final PatrolFinder titleAppBar = await appBar //
|
|
||||||
.$(title)
|
|
||||||
.waitUntilVisible();
|
|
||||||
expect(titleAppBar, findsOneWidget);
|
|
||||||
|
|
||||||
final PatrolFinder tab1 = await $(#TabView_Tab1) //
|
|
||||||
.waitUntilExists();
|
|
||||||
final PatrolFinder tab2 = await $(#TabView_Tab2) //
|
|
||||||
.waitUntilExists();
|
|
||||||
|
|
||||||
await tab2.tap();
|
|
||||||
await Future.delayed(const Duration(milliseconds: 500));
|
|
||||||
await tab1.tap();
|
|
||||||
|
|
||||||
final PatrolFinder listViewFinder = await $(VehicleHistoryScreen) //
|
|
||||||
.$(ListView)
|
|
||||||
.waitUntilVisible();
|
|
||||||
|
|
||||||
expect(listViewFinder, findsOneWidget);
|
|
||||||
|
|
||||||
final PatrolFinder entriesFinder = await $(listViewFinder)
|
|
||||||
.$(CardItemTemplateComponentWidget)
|
|
||||||
.waitUntilVisible();
|
|
||||||
|
|
||||||
expect(entriesFinder, findsWidgets);
|
|
||||||
await $.pumpAndSettle();
|
|
||||||
await Future.delayed(const Duration(milliseconds: 1000));
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Future<void> historyScreen() async {
|
|
||||||
patrolWidgetTest(
|
|
||||||
'historyScreen',
|
|
||||||
(PatrolTester tester) async {
|
|
||||||
$ = tester;
|
|
||||||
$.tester.printToConsole('Vehicle Page');
|
|
||||||
final PatrolFinder throwsException = $(Dialog).$(ThrowExceptionWidget);
|
|
||||||
|
|
||||||
await _loggedWithMultiLocalsAccount();
|
|
||||||
await _initVehicleModule();
|
|
||||||
await $.pumpAndSettle();
|
|
||||||
await $.pumpWidgetAndSettle(const App());
|
|
||||||
|
|
||||||
ff.navigatorKey.currentContext!.go('/vehiclesOnThePropertyPage');
|
|
||||||
|
|
||||||
final String title = MenuEntry.entries //
|
|
||||||
.where((entry) => entry.key == 'FRE-HUB-VEHICLES') //
|
|
||||||
.map((entry) => entry.name)
|
|
||||||
.first;
|
|
||||||
|
|
||||||
final PatrolFinder appBar = await $(AppBar) //
|
|
||||||
.waitUntilExists();
|
|
||||||
final PatrolFinder titleAppBar = await appBar //
|
|
||||||
.$(title)
|
|
||||||
.waitUntilVisible();
|
|
||||||
expect(titleAppBar, findsOneWidget);
|
|
||||||
|
|
||||||
final PatrolFinder listViewFinder = await $(VehicleHistoryScreen) //
|
|
||||||
.$(ListView)
|
|
||||||
.waitUntilVisible();
|
|
||||||
|
|
||||||
expect(listViewFinder, findsOneWidget);
|
|
||||||
|
|
||||||
final PatrolFinder entriesFinder = await $(listViewFinder)
|
|
||||||
.$(CardItemTemplateComponentWidget)
|
|
||||||
.waitUntilVisible();
|
|
||||||
|
|
||||||
expect(entriesFinder, findsWidgets);
|
|
||||||
await $.pumpAndSettle();
|
|
||||||
await $(entriesFinder.first)
|
|
||||||
.waitUntilVisible(timeout: const Duration(seconds: 1))
|
|
||||||
.tap(
|
|
||||||
settleTimeout: const Duration(seconds: 1),
|
|
||||||
settlePolicy: SettlePolicy.noSettle,
|
|
||||||
);
|
|
||||||
|
|
||||||
await $.pumpAndSettle(duration: Duration(milliseconds: 500));
|
|
||||||
final PatrolFinder detailsFinder =
|
|
||||||
await $(DetailsComponentWidget).waitUntilVisible();
|
|
||||||
expect(detailsFinder, findsOneWidget);
|
|
||||||
|
|
||||||
await _navigateBackUsingSystemGesture();
|
|
||||||
|
|
||||||
/// Iterable Test
|
|
||||||
// final int entriesCount = entriesFinder.evaluate().length;
|
|
||||||
// for (int i = 0; i < entriesCount; i++) {
|
|
||||||
// // await $(entriesFinder.at(i)).scrollTo();
|
|
||||||
|
|
||||||
// await $(entriesFinder.at(i))
|
|
||||||
// .waitUntilVisible(timeout: const Duration(seconds: 1))
|
|
||||||
// .tap(
|
|
||||||
// settleTimeout: const Duration(seconds: 1),
|
|
||||||
// settlePolicy: SettlePolicy.noSettle,
|
|
||||||
// );
|
|
||||||
|
|
||||||
// await $.pumpAndSettle(duration: Duration(milliseconds: 500));
|
|
||||||
// final PatrolFinder detailsFinder =
|
|
||||||
// await $(DetailsComponentWidget).waitUntilVisible();
|
|
||||||
// expect(detailsFinder, findsOneWidget);
|
|
||||||
|
|
||||||
// await _navigateBackUsingSystemGesture();
|
|
||||||
|
|
||||||
// // await $.native.pressBack().then((_) => $.pumpAndSettle());
|
|
||||||
// }
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Future<void> registerScreen() async {
|
|
||||||
patrolWidgetTest(
|
|
||||||
'registerScreen',
|
|
||||||
(PatrolTester tester) async {
|
|
||||||
$ = tester;
|
|
||||||
$.tester.printToConsole('Vehicle Register Page');
|
|
||||||
|
|
||||||
await _loggedWithMultiLocalsAccount();
|
|
||||||
await _initVehicleModule();
|
|
||||||
await $.pumpAndSettle();
|
|
||||||
await $.pumpWidgetAndSettle(const App());
|
|
||||||
|
|
||||||
ff.navigatorKey.currentContext!.go('/vehiclesOnThePropertyPage');
|
|
||||||
|
|
||||||
final PatrolFinder tab2 = await $(#TabView_Tab2) //
|
|
||||||
.waitUntilExists();
|
|
||||||
|
|
||||||
await tab2.tap();
|
|
||||||
|
|
||||||
final PatrolFinder licensePlateField =
|
|
||||||
await $(TextField).at(0).waitUntilVisible();
|
|
||||||
final PatrolFinder modelField =
|
|
||||||
await $(TextField).at(1).waitUntilVisible();
|
|
||||||
final PatrolFinder colorField =
|
|
||||||
await $(TextField).at(2).waitUntilVisible();
|
|
||||||
final PatrolFinder submitButton =
|
|
||||||
await $(SubmitButtonUtil).waitUntilVisible();
|
|
||||||
|
|
||||||
await licensePlateField.enterText('ABC1234');
|
|
||||||
await modelField.enterText('Voyage');
|
|
||||||
await colorField.enterText('Black');
|
|
||||||
await submitButton.tap();
|
|
||||||
|
|
||||||
await $.pumpAndSettle();
|
|
||||||
final PatrolFinder successDialog = await $(Dialog).waitUntilVisible();
|
|
||||||
expect(successDialog, findsOneWidget);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Future<void> updateScreen() async {
|
|
||||||
patrolWidgetTest(
|
|
||||||
'updateScreen',
|
|
||||||
(PatrolTester tester) async {
|
|
||||||
$ = tester;
|
|
||||||
$.tester.printToConsole('Vehicle Update Page');
|
|
||||||
|
|
||||||
await _loggedWithMultiLocalsAccount();
|
|
||||||
await _initVehicleModule();
|
|
||||||
await $.pumpAndSettle();
|
|
||||||
await $.pumpWidgetAndSettle(const App());
|
|
||||||
|
|
||||||
ff.navigatorKey.currentContext!.go('/vehiclesOnThePropertyPage');
|
|
||||||
|
|
||||||
final PatrolFinder tab1 = await $(#TabView_Tab1) //
|
|
||||||
.waitUntilExists();
|
|
||||||
|
|
||||||
await tab1.tap();
|
|
||||||
|
|
||||||
final PatrolFinder listViewFinder = await $(VehicleHistoryScreen) //
|
|
||||||
.$(ListView)
|
|
||||||
.waitUntilVisible();
|
|
||||||
|
|
||||||
expect(listViewFinder, findsOneWidget);
|
|
||||||
|
|
||||||
final PatrolFinder entriesFinder = await $(listViewFinder)
|
|
||||||
.$(CardItemTemplateComponentWidget)
|
|
||||||
.waitUntilVisible();
|
|
||||||
|
|
||||||
expect(entriesFinder, findsWidgets);
|
|
||||||
await $(entriesFinder.at(0)).tap();
|
|
||||||
|
|
||||||
final PatrolFinder editButton =
|
|
||||||
await $(FFButtonWidget).$('Edit').waitUntilVisible();
|
|
||||||
await editButton.tap();
|
|
||||||
|
|
||||||
final PatrolFinder licensePlateField =
|
|
||||||
await $(TextField).at(0).waitUntilVisible();
|
|
||||||
final PatrolFinder modelField =
|
|
||||||
await $(TextField).at(1).waitUntilVisible();
|
|
||||||
final PatrolFinder colorField =
|
|
||||||
await $(TextField).at(2).waitUntilVisible();
|
|
||||||
final PatrolFinder submitButton =
|
|
||||||
await $(SubmitButtonUtil).waitUntilVisible();
|
|
||||||
|
|
||||||
await licensePlateField.enterText('XYZ5678');
|
|
||||||
await modelField.enterText('Fiesta');
|
|
||||||
await colorField.enterText('Red');
|
|
||||||
await submitButton.tap();
|
|
||||||
|
|
||||||
await $.pumpAndSettle();
|
|
||||||
final PatrolFinder successDialog = await $(Dialog).waitUntilVisible();
|
|
||||||
expect(successDialog, findsOneWidget);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -5,15 +5,6 @@ import 'package:google_fonts/google_fonts.dart';
|
||||||
import 'package:hub/flutter_flow/flutter_flow_theme.dart';
|
import 'package:hub/flutter_flow/flutter_flow_theme.dart';
|
||||||
import 'package:hub/shared/utils/limited_text_size.dart';
|
import 'package:hub/shared/utils/limited_text_size.dart';
|
||||||
|
|
||||||
class UpperCaseTextFormatter extends TextInputFormatter {
|
|
||||||
@override
|
|
||||||
TextEditingValue formatEditUpdate(
|
|
||||||
TextEditingValue oldValue, TextEditingValue newValue) {
|
|
||||||
return TextEditingValue(
|
|
||||||
text: newValue.text.toUpperCase(), selection: newValue.selection);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ignore: must_be_immutable
|
// ignore: must_be_immutable
|
||||||
class CustomInputUtil extends StatefulWidget {
|
class CustomInputUtil extends StatefulWidget {
|
||||||
final TextEditingController? controller;
|
final TextEditingController? controller;
|
||||||
|
@ -29,25 +20,22 @@ class CustomInputUtil extends StatefulWidget {
|
||||||
final String? Function(String?)? validator;
|
final String? Function(String?)? validator;
|
||||||
final bool haveMaxLength;
|
final bool haveMaxLength;
|
||||||
final void Function(String)? onChanged;
|
final void Function(String)? onChanged;
|
||||||
final List<TextInputFormatter>? inputFormatters;
|
|
||||||
|
|
||||||
CustomInputUtil({
|
CustomInputUtil(
|
||||||
super.key,
|
{super.key,
|
||||||
this.controller,
|
this.controller,
|
||||||
required this.labelText,
|
required this.labelText,
|
||||||
required this.hintText,
|
required this.hintText,
|
||||||
required this.suffixIcon,
|
required this.suffixIcon,
|
||||||
this.autoFocus = false,
|
this.autoFocus = false,
|
||||||
required this.focusNode,
|
required this.focusNode,
|
||||||
this.onChanged,
|
this.onChanged,
|
||||||
this.textInputAction = TextInputAction.next,
|
this.textInputAction = TextInputAction.next,
|
||||||
this.keyboardType = TextInputType.text,
|
this.keyboardType = TextInputType.text,
|
||||||
this.maxLength = 80,
|
this.maxLength = 80,
|
||||||
this.validator,
|
this.validator,
|
||||||
this.obscureText,
|
this.obscureText,
|
||||||
this.inputFormatters,
|
required this.haveMaxLength});
|
||||||
required this.haveMaxLength,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<CustomInputUtil> createState() => _CustomInputUtilState();
|
State<CustomInputUtil> createState() => _CustomInputUtilState();
|
||||||
|
@ -164,7 +152,6 @@ class _CustomInputUtilState extends State<CustomInputUtil> {
|
||||||
keyboardType: widget.keyboardType,
|
keyboardType: widget.keyboardType,
|
||||||
inputFormatters: [
|
inputFormatters: [
|
||||||
LengthLimitingTextInputFormatter(widget.maxLength),
|
LengthLimitingTextInputFormatter(widget.maxLength),
|
||||||
if (widget.inputFormatters != null) ...widget.inputFormatters!
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
|
@ -10,7 +10,7 @@ class TabViewUtil extends StatelessWidget {
|
||||||
String labelTab1;
|
String labelTab1;
|
||||||
String labelTab2;
|
String labelTab2;
|
||||||
final TabController controller;
|
final TabController controller;
|
||||||
final Function([bool]) onEditingChanged;
|
final Function(bool) onEditingChanged;
|
||||||
Widget widget1;
|
Widget widget1;
|
||||||
Widget widget2;
|
Widget widget2;
|
||||||
|
|
||||||
|
@ -49,17 +49,15 @@ class TabViewUtil extends StatelessWidget {
|
||||||
padding: const EdgeInsets.all(4.0),
|
padding: const EdgeInsets.all(4.0),
|
||||||
tabs: [
|
tabs: [
|
||||||
Tab(
|
Tab(
|
||||||
key: ValueKey('TabView_Tab1'),
|
|
||||||
text: labelTab1,
|
text: labelTab1,
|
||||||
),
|
),
|
||||||
Tab(
|
Tab(
|
||||||
key: ValueKey('TabView_Tab2'),
|
|
||||||
text: labelTab2,
|
text: labelTab2,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
controller: controller,
|
controller: controller,
|
||||||
onTap: (i) async {
|
onTap: (i) async {
|
||||||
onEditingChanged();
|
if (i == 1) onEditingChanged(false);
|
||||||
[() async {}, () async {}][i]();
|
[() async {}, () async {}][i]();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
|
@ -209,7 +209,6 @@ class _BottomArrowLinkedLocalsComponentWidgetState
|
||||||
return CardItemTemplateComponentWidget(
|
return CardItemTemplateComponentWidget(
|
||||||
key: ValueKey<String>(local['CLI_NOME']),
|
key: ValueKey<String>(local['CLI_NOME']),
|
||||||
imagePath: _imagePath(local),
|
imagePath: _imagePath(local),
|
||||||
icon: null,
|
|
||||||
labelsHashMap: _labelsHashMap(local),
|
labelsHashMap: _labelsHashMap(local),
|
||||||
statusHashMap: [_statusHashMap(local)],
|
statusHashMap: [_statusHashMap(local)],
|
||||||
onTapCardItemAction: () async {
|
onTapCardItemAction: () async {
|
||||||
|
|
|
@ -12,74 +12,18 @@ import 'card_item_template_component_model.dart';
|
||||||
|
|
||||||
export 'card_item_template_component_model.dart';
|
export 'card_item_template_component_model.dart';
|
||||||
|
|
||||||
class FreCardIcon extends StatelessWidget {
|
|
||||||
final double height;
|
|
||||||
final double width;
|
|
||||||
final Icon icon;
|
|
||||||
|
|
||||||
const FreCardIcon({
|
|
||||||
super.key,
|
|
||||||
required this.height,
|
|
||||||
required this.width,
|
|
||||||
required this.icon,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return SizedBox(
|
|
||||||
height: height,
|
|
||||||
width: width,
|
|
||||||
child: icon,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class FreCardPin extends StatelessWidget {
|
|
||||||
final double height;
|
|
||||||
final double width;
|
|
||||||
final Color color;
|
|
||||||
|
|
||||||
const FreCardPin({
|
|
||||||
super.key,
|
|
||||||
required this.height,
|
|
||||||
required this.width,
|
|
||||||
required this.color,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Padding(
|
|
||||||
padding: const EdgeInsets.all(8.0),
|
|
||||||
child: Container(
|
|
||||||
height: height,
|
|
||||||
width: width,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: color,
|
|
||||||
shape: BoxShape.circle,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class CardItemTemplateComponentWidget extends StatefulWidget {
|
class CardItemTemplateComponentWidget extends StatefulWidget {
|
||||||
const CardItemTemplateComponentWidget({
|
const CardItemTemplateComponentWidget({
|
||||||
super.key,
|
super.key,
|
||||||
required this.labelsHashMap,
|
required this.labelsHashMap,
|
||||||
required this.statusHashMap,
|
required this.statusHashMap,
|
||||||
this.imagePath,
|
required this.imagePath,
|
||||||
this.icon,
|
|
||||||
this.pin,
|
|
||||||
this.itemWidthFactor = 0.25,
|
|
||||||
required this.onTapCardItemAction,
|
required this.onTapCardItemAction,
|
||||||
});
|
});
|
||||||
|
|
||||||
final Map<String, String>? labelsHashMap;
|
final Map<String, String>? labelsHashMap;
|
||||||
final List<Map<String, Color>?> statusHashMap;
|
final List<Map<String, Color>?> statusHashMap;
|
||||||
final String? imagePath;
|
final String? imagePath;
|
||||||
final FreCardIcon? icon;
|
|
||||||
final FreCardPin? pin;
|
|
||||||
final double itemWidthFactor;
|
|
||||||
final Future Function()? onTapCardItemAction;
|
final Future Function()? onTapCardItemAction;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -181,24 +125,9 @@ class _CardItemTemplateComponentWidgetState
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _generateIcon() {
|
|
||||||
return Column(
|
|
||||||
children: [
|
|
||||||
widget.icon!,
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _generatePin() {
|
|
||||||
return widget.pin!;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Widget> _generateStatus() {
|
List<Widget> _generateStatus() {
|
||||||
double limitedBodyTextSize = LimitedFontSizeUtil.getBodyFontSize(context);
|
double limitedBodyTextSize = LimitedFontSizeUtil.getBodyFontSize(context);
|
||||||
|
|
||||||
return statusLinkedHashMap.expand((statusLinked) {
|
return statusLinkedHashMap.expand((statusLinked) {
|
||||||
log('statusHashMap: ${statusLinked.length}');
|
|
||||||
|
|
||||||
return statusLinked.entries.map((entry) {
|
return statusLinked.entries.map((entry) {
|
||||||
final text = entry.key;
|
final text = entry.key;
|
||||||
final color = entry.value;
|
final color = entry.value;
|
||||||
|
@ -207,7 +136,7 @@ class _CardItemTemplateComponentWidgetState
|
||||||
message: text,
|
message: text,
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: const EdgeInsets.all(5),
|
padding: const EdgeInsets.all(5),
|
||||||
width: MediaQuery.of(context).size.width * widget.itemWidthFactor,
|
width: MediaQuery.of(context).size.width * 0.25,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: color,
|
color: color,
|
||||||
borderRadius: BorderRadius.circular(5),
|
borderRadius: BorderRadius.circular(5),
|
||||||
|
@ -233,50 +162,38 @@ class _CardItemTemplateComponentWidgetState
|
||||||
return LayoutBuilder(
|
return LayoutBuilder(
|
||||||
builder: (context, constraints) {
|
builder: (context, constraints) {
|
||||||
if (constraints.maxWidth > 360) {
|
if (constraints.maxWidth > 360) {
|
||||||
return Column(
|
return Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
mainAxisSize: MainAxisSize.max,
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Row(
|
Expanded(
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.max,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [if (widget.pin != null) _generatePin()]),
|
mainAxisSize: MainAxisSize.min,
|
||||||
Row(
|
children: [
|
||||||
mainAxisSize: MainAxisSize.max,
|
..._generateLabels(),
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
SizedBox(height: 3),
|
||||||
children: [
|
Wrap(
|
||||||
Expanded(
|
spacing: 8,
|
||||||
child: Column(
|
runSpacing: 4,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
children: _generateStatus(),
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
..._generateLabels(),
|
|
||||||
Wrap(
|
|
||||||
spacing: 8,
|
|
||||||
runSpacing: 4,
|
|
||||||
children: _generateStatus(),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
.addToEnd(const SizedBox(height: 5))
|
|
||||||
.divide(const SizedBox(height: 3))
|
|
||||||
.addToStart(const SizedBox(height: 5)),
|
|
||||||
),
|
),
|
||||||
),
|
]
|
||||||
if (widget.icon != null) _generateIcon(),
|
.addToEnd(const SizedBox(height: 5))
|
||||||
if (widget.imagePath != null) _generateImage()
|
.divide(const SizedBox(height: 1))
|
||||||
]
|
.addToStart(const SizedBox(height: 5)),
|
||||||
.addToEnd(const SizedBox(width: 10))
|
),
|
||||||
.addToStart(const SizedBox(width: 10)),
|
|
||||||
),
|
),
|
||||||
].addToStart(SizedBox(height: 5)).addToEnd(SizedBox(height: 5)),
|
if (widget.imagePath != null) _generateImage(),
|
||||||
|
]
|
||||||
|
.addToEnd(const SizedBox(width: 10))
|
||||||
|
.addToStart(const SizedBox(width: 10)),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return Column(
|
return Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
if (widget.imagePath != null) _generateImage(),
|
if (widget.imagePath != null) _generateImage(),
|
||||||
if (widget.icon != null) _generateIcon(),
|
|
||||||
Container(
|
Container(
|
||||||
padding: const EdgeInsets.all(8),
|
padding: const EdgeInsets.all(8),
|
||||||
child: Column(
|
child: Column(
|
||||||
|
|
|
@ -3,7 +3,6 @@ import 'dart:collection';
|
||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:google_fonts/google_fonts.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/components/templates_components/details_component/details_component_model.dart';
|
import 'package:hub/components/templates_components/details_component/details_component_model.dart';
|
||||||
import 'package:hub/flutter_flow/flutter_flow_theme.dart';
|
import 'package:hub/flutter_flow/flutter_flow_theme.dart';
|
||||||
import 'package:hub/flutter_flow/flutter_flow_util.dart';
|
import 'package:hub/flutter_flow/flutter_flow_util.dart';
|
||||||
|
@ -15,7 +14,6 @@ class DetailsComponentWidget extends StatefulWidget {
|
||||||
required this.labelsHashMap,
|
required this.labelsHashMap,
|
||||||
required this.statusHashMap,
|
required this.statusHashMap,
|
||||||
this.imagePath,
|
this.imagePath,
|
||||||
this.icon,
|
|
||||||
this.onTapCardItemAction,
|
this.onTapCardItemAction,
|
||||||
required this.buttons,
|
required this.buttons,
|
||||||
});
|
});
|
||||||
|
@ -25,7 +23,6 @@ class DetailsComponentWidget extends StatefulWidget {
|
||||||
final String? imagePath;
|
final String? imagePath;
|
||||||
final Future Function()? onTapCardItemAction;
|
final Future Function()? onTapCardItemAction;
|
||||||
final List<Widget>? buttons;
|
final List<Widget>? buttons;
|
||||||
final FreCardIcon? icon;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<DetailsComponentWidget> createState() => _DetailsComponentWidgetState();
|
State<DetailsComponentWidget> createState() => _DetailsComponentWidgetState();
|
||||||
|
@ -100,16 +97,6 @@ class _DetailsComponentWidgetState extends State<DetailsComponentWidget> {
|
||||||
useOldImageOnUrlChange: true,
|
useOldImageOnUrlChange: true,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (widget.icon != null && widget.icon != '')
|
|
||||||
Container(
|
|
||||||
width: MediaQuery.of(context).size.width * 0.3,
|
|
||||||
height: MediaQuery.of(context).size.width * 0.3,
|
|
||||||
clipBehavior: Clip.antiAlias,
|
|
||||||
decoration: const BoxDecoration(
|
|
||||||
shape: BoxShape.circle,
|
|
||||||
),
|
|
||||||
child: widget.icon!,
|
|
||||||
),
|
|
||||||
SizedBox(height: MediaQuery.of(context).size.height * 0.03),
|
SizedBox(height: MediaQuery.of(context).size.height * 0.03),
|
||||||
Row(
|
Row(
|
||||||
children: statusLinkedHashMap.expand((linkedHashMap) {
|
children: statusLinkedHashMap.expand((linkedHashMap) {
|
||||||
|
@ -124,7 +111,6 @@ class _DetailsComponentWidgetState extends State<DetailsComponentWidget> {
|
||||||
autofocus: false,
|
autofocus: false,
|
||||||
canRequestFocus: false,
|
canRequestFocus: false,
|
||||||
readOnly: true,
|
readOnly: true,
|
||||||
initialValue: item.key,
|
|
||||||
obscureText: false,
|
obscureText: false,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
isDense: true,
|
isDense: true,
|
||||||
|
@ -136,7 +122,7 @@ class _DetailsComponentWidgetState extends State<DetailsComponentWidget> {
|
||||||
),
|
),
|
||||||
filled: true,
|
filled: true,
|
||||||
fillColor: item.value,
|
fillColor: item.value,
|
||||||
// labelText: item.key,
|
labelText: item.key,
|
||||||
labelStyle: FlutterFlowTheme.of(context)
|
labelStyle: FlutterFlowTheme.of(context)
|
||||||
.labelMedium
|
.labelMedium
|
||||||
.override(
|
.override(
|
||||||
|
@ -175,16 +161,14 @@ class _DetailsComponentWidgetState extends State<DetailsComponentWidget> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
style: FlutterFlowTheme.of(context)
|
style: FlutterFlowTheme.of(context)
|
||||||
.labelMedium
|
.bodyMedium
|
||||||
.override(
|
.override(
|
||||||
fontFamily: FlutterFlowTheme.of(context)
|
fontFamily: FlutterFlowTheme.of(context)
|
||||||
.labelMediumFamily,
|
.bodyMediumFamily,
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
color: FlutterFlowTheme.of(context).info,
|
color: FlutterFlowTheme.of(context).info,
|
||||||
letterSpacing: 0.0,
|
letterSpacing: 0.0,
|
||||||
useGoogleFonts: GoogleFonts.asMap().containsKey(
|
useGoogleFonts: GoogleFonts.asMap().containsKey(
|
||||||
FlutterFlowTheme.of(context)
|
FlutterFlowTheme.of(context).bodyMediumFamily,
|
||||||
.labelMediumFamily,
|
|
||||||
),
|
),
|
||||||
fontSize: limitedBodyFontSize,
|
fontSize: limitedBodyFontSize,
|
||||||
),
|
),
|
||||||
|
|
|
@ -34,7 +34,6 @@ class RegisiterVistorTemplateComponentWidget extends StatefulWidget {
|
||||||
class _RegisiterVistorTemplateComponentWidgetState
|
class _RegisiterVistorTemplateComponentWidgetState
|
||||||
extends State<RegisiterVistorTemplateComponentWidget> {
|
extends State<RegisiterVistorTemplateComponentWidget> {
|
||||||
late RegisiterVistorTemplateComponentModel _model;
|
late RegisiterVistorTemplateComponentModel _model;
|
||||||
final bool _isLoading = false;
|
|
||||||
final scaffoldKey = GlobalKey<ScaffoldState>();
|
final scaffoldKey = GlobalKey<ScaffoldState>();
|
||||||
|
|
||||||
bool _isVisitorRegistered = false;
|
bool _isVisitorRegistered = false;
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
class DeadCode {
|
||||||
|
final String? desc;
|
||||||
|
|
||||||
|
const DeadCode([this.desc = '']);
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
export 'anotations.dart';
|
|
@ -11,7 +11,7 @@ import 'package:hub/features/storage/index.dart';
|
||||||
|
|
||||||
import 'package:hub/shared/utils/log_util.dart';
|
import 'package:hub/shared/utils/log_util.dart';
|
||||||
import 'package:hub/shared/utils/validator_util.dart';
|
import 'package:hub/shared/utils/validator_util.dart';
|
||||||
import 'package:hub/shared/widgets.dart';
|
import 'package:hub/shared/widgets/widgets.dart';
|
||||||
|
|
||||||
import '/flutter_flow/flutter_flow_util.dart';
|
import '/flutter_flow/flutter_flow_util.dart';
|
||||||
import 'api_manager.dart';
|
import 'api_manager.dart';
|
||||||
|
@ -75,187 +75,6 @@ class FreAccessWSGlobal extends Api {
|
||||||
@override
|
@override
|
||||||
GetLicense getLicense = GetLicense();
|
GetLicense getLicense = GetLicense();
|
||||||
static GetProvSchedules getProvSchedules = GetProvSchedules();
|
static GetProvSchedules getProvSchedules = GetProvSchedules();
|
||||||
static RegisterVehicle registerVehicle = RegisterVehicle();
|
|
||||||
static UpdateVehicle updateVehicle = UpdateVehicle();
|
|
||||||
static DeleteVehicle deleteVehicle = DeleteVehicle();
|
|
||||||
static CancelDeleteVehicle cancelDelete = CancelDeleteVehicle();
|
|
||||||
static GetPDF getPDF = GetPDF();
|
|
||||||
static GetCategories getCategories = GetCategories();
|
|
||||||
static GetDocuments getDocuments = GetDocuments();
|
|
||||||
}
|
|
||||||
|
|
||||||
class CancelDeleteVehicle {
|
|
||||||
Future<ApiCallResponse> call({
|
|
||||||
required final int vehicleId,
|
|
||||||
required final String licensePlate,
|
|
||||||
required final String model,
|
|
||||||
required final String color,
|
|
||||||
}) async {
|
|
||||||
final String baseUrl = FreAccessWSGlobal.getBaseUrl();
|
|
||||||
final String devUUID =
|
|
||||||
(await StorageHelper().get(ProfileStorageKey.devUUID.key)) ?? '';
|
|
||||||
final String userUUID =
|
|
||||||
(await StorageHelper().get(ProfileStorageKey.userUUID.key)) ?? '';
|
|
||||||
final String cliID =
|
|
||||||
(await StorageHelper().get(ProfileStorageKey.clientUUID.key)) ?? '';
|
|
||||||
const String atividade = 'cancelDeleteVehicleRequest';
|
|
||||||
|
|
||||||
return await ApiManager.instance.makeApiCall(
|
|
||||||
callName: atividade,
|
|
||||||
apiUrl: '$baseUrl/processRequest.php',
|
|
||||||
callType: ApiCallType.POST,
|
|
||||||
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
|
|
||||||
params: {
|
|
||||||
'devUUID': devUUID,
|
|
||||||
'userUUID': userUUID,
|
|
||||||
'cliID': cliID,
|
|
||||||
'atividade': atividade,
|
|
||||||
'vehicleId': vehicleId,
|
|
||||||
'licensePlate': licensePlate,
|
|
||||||
'model': model,
|
|
||||||
'color': color
|
|
||||||
},
|
|
||||||
bodyType: BodyType.X_WWW_FORM_URL_ENCODED,
|
|
||||||
returnBody: true,
|
|
||||||
encodeBodyUtf8: false,
|
|
||||||
decodeUtf8: false,
|
|
||||||
cache: false,
|
|
||||||
isStreamingApi: false,
|
|
||||||
alwaysAllowBody: false,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class DeleteVehicle {
|
|
||||||
Future<ApiCallResponse> call({
|
|
||||||
required final int vehicleId,
|
|
||||||
required final String licensePlate,
|
|
||||||
required final String model,
|
|
||||||
required final String color,
|
|
||||||
}) async {
|
|
||||||
final String baseUrl = FreAccessWSGlobal.getBaseUrl();
|
|
||||||
final String devUUID =
|
|
||||||
(await StorageHelper().get(ProfileStorageKey.devUUID.key)) ?? '';
|
|
||||||
final String userUUID =
|
|
||||||
(await StorageHelper().get(ProfileStorageKey.userUUID.key)) ?? '';
|
|
||||||
final String cliID =
|
|
||||||
(await StorageHelper().get(ProfileStorageKey.clientUUID.key)) ?? '';
|
|
||||||
const String atividade = 'deleteVehicle';
|
|
||||||
|
|
||||||
return await ApiManager.instance.makeApiCall(
|
|
||||||
callName: 'deleteVehicle',
|
|
||||||
apiUrl: '$baseUrl/processRequest.php',
|
|
||||||
callType: ApiCallType.POST,
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/x-www-form-urlencoded',
|
|
||||||
},
|
|
||||||
params: {
|
|
||||||
'devUUID': devUUID,
|
|
||||||
'userUUID': userUUID,
|
|
||||||
'cliID': cliID,
|
|
||||||
'atividade': atividade,
|
|
||||||
'vehicleId': vehicleId,
|
|
||||||
'licensePlate': licensePlate,
|
|
||||||
'model': model,
|
|
||||||
'color': color
|
|
||||||
},
|
|
||||||
bodyType: BodyType.X_WWW_FORM_URL_ENCODED,
|
|
||||||
returnBody: true,
|
|
||||||
encodeBodyUtf8: false,
|
|
||||||
decodeUtf8: false,
|
|
||||||
cache: false,
|
|
||||||
isStreamingApi: false,
|
|
||||||
alwaysAllowBody: false,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class RegisterVehicle {
|
|
||||||
Future<ApiCallResponse> call({
|
|
||||||
final String? licensePlate,
|
|
||||||
final String? color,
|
|
||||||
final String? model,
|
|
||||||
}) async {
|
|
||||||
final String baseUrl = FreAccessWSGlobal.getBaseUrl();
|
|
||||||
|
|
||||||
final String devUUID =
|
|
||||||
(await StorageHelper().get(ProfileStorageKey.devUUID.key)) ?? '';
|
|
||||||
final String userUUID =
|
|
||||||
(await StorageHelper().get(ProfileStorageKey.userUUID.key)) ?? '';
|
|
||||||
final String cliID =
|
|
||||||
(await StorageHelper().get(ProfileStorageKey.clientUUID.key)) ?? '';
|
|
||||||
const String atividade = 'insertVehicle';
|
|
||||||
|
|
||||||
return await ApiManager.instance.makeApiCall(
|
|
||||||
callName: 'registerVehicle',
|
|
||||||
apiUrl: '$baseUrl/processRequest.php',
|
|
||||||
callType: ApiCallType.POST,
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/x-www-form-urlencoded',
|
|
||||||
},
|
|
||||||
params: {
|
|
||||||
'devUUID': devUUID,
|
|
||||||
'userUUID': userUUID,
|
|
||||||
'cliID': cliID,
|
|
||||||
'atividade': atividade,
|
|
||||||
'licensePlate': licensePlate,
|
|
||||||
'color': color,
|
|
||||||
'model': model,
|
|
||||||
},
|
|
||||||
bodyType: BodyType.X_WWW_FORM_URL_ENCODED,
|
|
||||||
returnBody: true,
|
|
||||||
encodeBodyUtf8: false,
|
|
||||||
decodeUtf8: false,
|
|
||||||
cache: false,
|
|
||||||
isStreamingApi: false,
|
|
||||||
alwaysAllowBody: false,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class UpdateVehicle {
|
|
||||||
Future<ApiCallResponse> call({
|
|
||||||
required final int vehicleId,
|
|
||||||
final String? licensePlate,
|
|
||||||
final String? color,
|
|
||||||
final String? model,
|
|
||||||
}) async {
|
|
||||||
final String baseUrl = FreAccessWSGlobal.getBaseUrl();
|
|
||||||
final String devUUID =
|
|
||||||
(await StorageHelper().get(ProfileStorageKey.devUUID.key)) ?? '';
|
|
||||||
final String userUUID =
|
|
||||||
(await StorageHelper().get(ProfileStorageKey.userUUID.key)) ?? '';
|
|
||||||
final String cliID =
|
|
||||||
(await StorageHelper().get(ProfileStorageKey.clientUUID.key)) ?? '';
|
|
||||||
const String atividade = 'updateVehicleToInsertRequest';
|
|
||||||
|
|
||||||
return await ApiManager.instance.makeApiCall(
|
|
||||||
callName: 'updateVehicle',
|
|
||||||
apiUrl: '$baseUrl/processRequest.php',
|
|
||||||
callType: ApiCallType.POST,
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/x-www-form-urlencoded',
|
|
||||||
},
|
|
||||||
params: {
|
|
||||||
'devUUID': devUUID,
|
|
||||||
'userUUID': userUUID,
|
|
||||||
'cliID': cliID,
|
|
||||||
'atividade': atividade,
|
|
||||||
'licensePlate': licensePlate,
|
|
||||||
'color': color,
|
|
||||||
'model': model,
|
|
||||||
'vehicleId': vehicleId
|
|
||||||
},
|
|
||||||
bodyType: BodyType.X_WWW_FORM_URL_ENCODED,
|
|
||||||
returnBody: true,
|
|
||||||
encodeBodyUtf8: false,
|
|
||||||
decodeUtf8: false,
|
|
||||||
cache: false,
|
|
||||||
isStreamingApi: false,
|
|
||||||
alwaysAllowBody: false,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static GetCategories getCategories = GetCategories();
|
static GetCategories getCategories = GetCategories();
|
||||||
static GetDocuments getDocuments = GetDocuments();
|
static GetDocuments getDocuments = GetDocuments();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:core';
|
import 'dart:core';
|
||||||
|
import 'dart:developer';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
@ -495,11 +496,11 @@ class ApiManager {
|
||||||
result = ApiCallResponse(null, {}, -1, exception: e);
|
result = ApiCallResponse(null, {}, -1, exception: e);
|
||||||
}
|
}
|
||||||
|
|
||||||
print('API Call: $callName');
|
log('API Call: $callName');
|
||||||
print('URL: $apiUrl');
|
log('URL: $apiUrl');
|
||||||
print('Headers: $headers');
|
log('Headers: $headers');
|
||||||
print('Params: $params');
|
log('Params: $params');
|
||||||
print('Response: ${result.jsonBody}');
|
log('Response: ${result.jsonBody}');
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,17 @@
|
||||||
import 'dart:developer';
|
import 'dart:developer';
|
||||||
|
|
||||||
import 'package:easy_debounce/easy_debounce.dart';
|
import 'package:easy_debounce/easy_debounce.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:hub/components/templates_components/details_component/details_component_widget.dart';
|
import 'package:hub/components/templates_components/details_component/details_component_widget.dart';
|
||||||
import 'package:hub/features/backend/index.dart';
|
import 'package:hub/features/backend/index.dart';
|
||||||
import 'package:hub/flutter_flow/index.dart';
|
import 'package:hub/flutter_flow/index.dart';
|
||||||
import 'package:hub/shared/extensions.dart';
|
import 'package:hub/shared/extensions/index.dart';
|
||||||
import 'package:hub/shared/utils.dart';
|
import 'package:hub/shared/utils/index.dart';
|
||||||
import 'package:hub/shared/widgets.dart';
|
import 'package:hub/shared/widgets/widgets.dart';
|
||||||
|
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:flutter_rx_bloc/flutter_rx_bloc.dart';
|
import 'package:flutter_rx_bloc/flutter_rx_bloc.dart';
|
||||||
|
|
||||||
import 'package:rx_bloc/rx_bloc.dart';
|
import 'package:rx_bloc/rx_bloc.dart';
|
||||||
import 'package:rxdart/rxdart.dart' as rx;
|
import 'package:rxdart/rxdart.dart' as rx;
|
||||||
|
|
||||||
|
@ -131,7 +134,7 @@ class DocumentManagerScreen extends StatelessScreen {
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: EnhancedListView<Document, SearchField, Category, Query>(
|
child: EnhancedListView<Document, SearchField, Category, Query>(
|
||||||
key: model.enhancedListViewKey,
|
key: model.vehicleScreenManager,
|
||||||
controller: controller,
|
controller: controller,
|
||||||
repository: repository,
|
repository: repository,
|
||||||
),
|
),
|
||||||
|
@ -164,14 +167,15 @@ class _DocumentViewerScreenState extends ScreenState<DocumentViewerScreen> {
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
backAction() => widget.bloc.events.unselectDocument();
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final String title = widget.doc.$1.description;
|
final String title = widget.doc.$1.description;
|
||||||
final theme = FlutterFlowTheme.of(context);
|
final theme = FlutterFlowTheme.of(context);
|
||||||
final locale = FFLocalizations.of(context);
|
final locale = FFLocalizations.of(context);
|
||||||
|
final Color color = widget.doc.$1.category.color;
|
||||||
|
;
|
||||||
|
|
||||||
|
backAction() => widget.bloc.events.unselectDocument();
|
||||||
infoAction() => DetailsComponentWidget(
|
infoAction() => DetailsComponentWidget(
|
||||||
buttons: [],
|
buttons: [],
|
||||||
statusHashMap: [
|
statusHashMap: [
|
||||||
|
@ -226,7 +230,6 @@ class _DocumentViewerScreenState extends ScreenState<DocumentViewerScreen> {
|
||||||
return ReadView(
|
return ReadView(
|
||||||
title: widget.doc.$1.description,
|
title: widget.doc.$1.description,
|
||||||
url: widget.doc.$2.toString(),
|
url: widget.doc.$2.toString(),
|
||||||
onError: backAction,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -240,25 +243,28 @@ class DocumentModel extends FlutterFlowModel<DocumentPage> {
|
||||||
DocumentModel(this.bloc);
|
DocumentModel(this.bloc);
|
||||||
|
|
||||||
late EnhancedListViewKey<Document, SearchField, Category, Query>
|
late EnhancedListViewKey<Document, SearchField, Category, Query>
|
||||||
enhancedListViewKey;
|
vehicleScreenManager;
|
||||||
late EnhancedCarouselViewKey<Category> carouselViewKey;
|
|
||||||
|
|
||||||
late DocumentKey vehicleScreenViewer;
|
late DocumentKey vehicleScreenViewer;
|
||||||
|
late PagingController<int, Document> _pagingController;
|
||||||
|
|
||||||
|
late bool categoryIsSelected;
|
||||||
|
|
||||||
/// ------------
|
/// ------------
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState(BuildContext context) {
|
void initState(BuildContext context) {
|
||||||
enhancedListViewKey =
|
vehicleScreenManager =
|
||||||
EnhancedListViewKey<Document, SearchField, Category, Query>();
|
EnhancedListViewKey<Document, SearchField, Category, Query>();
|
||||||
carouselViewKey = EnhancedCarouselViewKey<Category>();
|
|
||||||
vehicleScreenViewer = DocumentKey();
|
vehicleScreenViewer = DocumentKey();
|
||||||
|
_pagingController = PagingController<int, Document>(firstPageKey: 1);
|
||||||
|
|
||||||
|
categoryIsSelected = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
enhancedListViewKey.currentState?.dispose();
|
_pagingController.dispose();
|
||||||
carouselViewKey.currentState?.dispose();
|
vehicleScreenManager.currentState?.dispose();
|
||||||
vehicleScreenViewer.currentState?.dispose();
|
vehicleScreenViewer.currentState?.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -332,17 +338,14 @@ class DocumentModel extends FlutterFlowModel<DocumentPage> {
|
||||||
Widget itemFooterBuilder<T extends Category>(
|
Widget itemFooterBuilder<T extends Category>(
|
||||||
Future<List<T?>> Function() fetchData) =>
|
Future<List<T?>> Function() fetchData) =>
|
||||||
Builder(builder: (context) {
|
Builder(builder: (context) {
|
||||||
CategoryComponent categoryItemBuilder<T>(T? item, bool isSelected) {
|
CategoryComponent categoryItemBuilder<T>(T? item) {
|
||||||
return CategoryComponent(
|
return CategoryComponent(category: item! as Category);
|
||||||
category: item! as Category, isSelected: isSelected);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return EnhancedCarouselView<T>(
|
return EnhancedCarouselView<T>(
|
||||||
key: carouselViewKey,
|
|
||||||
dataProvider: fetchData,
|
dataProvider: fetchData,
|
||||||
itemBuilder: categoryItemBuilder,
|
itemBuilder: categoryItemBuilder,
|
||||||
filter: filterByCategory<T>,
|
filter: filterByCategory<T>,
|
||||||
showIndicator: true,
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -455,14 +458,18 @@ class DocumentModel extends FlutterFlowModel<DocumentPage> {
|
||||||
/// [Filter]
|
/// [Filter]
|
||||||
|
|
||||||
void filterBySearchBar<T>(T query, BuildContext context) {
|
void filterBySearchBar<T>(T query, BuildContext context) {
|
||||||
final enhancedListViewState = enhancedListViewKey.currentState;
|
final key = vehicleScreenManager.currentState;
|
||||||
return enhancedListViewState?.filterBodyItems(query);
|
return key?.filterBodyItems(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
void filterByCategory<T>(T? query, BuildContext context) {
|
void filterByCategory<T>(T query, BuildContext context) {
|
||||||
final enhancedListViewState = enhancedListViewKey.currentState;
|
final key = vehicleScreenManager.currentState;
|
||||||
|
|
||||||
enhancedListViewState?.filterBodyItems(query);
|
categoryIsSelected
|
||||||
|
? key?.filterBodyItems(null)
|
||||||
|
: key?.filterBodyItems(query);
|
||||||
|
|
||||||
|
categoryIsSelected = !categoryIsSelected;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// [Exception]
|
/// [Exception]
|
||||||
|
@ -655,71 +662,64 @@ class DocumentComponent extends StatelessComponent {
|
||||||
final description = document.description;
|
final description = document.description;
|
||||||
final title = document.category.title;
|
final title = document.category.title;
|
||||||
const double size = 20;
|
const double size = 20;
|
||||||
final date = ValidatorUtil.toLocalDateTime(
|
|
||||||
'yyyy-MM-dd',
|
|
||||||
document.updatedAt,
|
|
||||||
);
|
|
||||||
|
|
||||||
return Tooltip(
|
return InkWell(
|
||||||
message: description,
|
onTap: () => onPressed(document, context),
|
||||||
child: InkWell(
|
enableFeedback: true,
|
||||||
onTap: () => onPressed(document, context),
|
overlayColor: WidgetStateProperty.all<Color>(primaryColor),
|
||||||
enableFeedback: true,
|
borderRadius: BorderRadius.circular(10),
|
||||||
overlayColor: WidgetStateProperty.all<Color>(primaryColor),
|
child: SizedBox(
|
||||||
borderRadius: BorderRadius.circular(10),
|
height: boxHeight,
|
||||||
child: SizedBox(
|
child: Row(
|
||||||
height: boxHeight,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
child: Row(
|
spacing: size,
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
children: [
|
||||||
spacing: size,
|
// const SizedBox(width: 10),
|
||||||
children: [
|
Icon(icon, color: color),
|
||||||
// const SizedBox(width: 10),
|
|
||||||
Icon(icon, color: color),
|
|
||||||
|
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Tooltip(
|
Tooltip(
|
||||||
message: description,
|
message: description,
|
||||||
child: AutoText(
|
child: AutoText(
|
||||||
description,
|
description,
|
||||||
style: textStyleMajor,
|
style: textStyleMajor,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
|
||||||
),
|
),
|
||||||
Tooltip(
|
),
|
||||||
message: date,
|
AutoText(
|
||||||
child: AutoText(
|
ValidatorUtil.toLocalDateTime(
|
||||||
date,
|
'yyyy-MM-dd',
|
||||||
style: textStyleMinor,
|
document.updatedAt,
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
style: textStyleMinor,
|
||||||
),
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
Expanded(
|
),
|
||||||
child: Column(
|
Expanded(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
_buildTooltip(title, color, context, constraints),
|
children: [
|
||||||
],
|
_buildTooltip(title, color, context, constraints),
|
||||||
),
|
],
|
||||||
),
|
),
|
||||||
// const SizedBox(width: 10),
|
),
|
||||||
Center(
|
// const SizedBox(width: 10),
|
||||||
child: Icon(
|
Center(
|
||||||
Icons.arrow_right,
|
child: Icon(
|
||||||
color: primaryText,
|
Icons.arrow_right,
|
||||||
),
|
color: primaryText,
|
||||||
),
|
),
|
||||||
] //
|
),
|
||||||
.addToStart(space)
|
] //
|
||||||
.addToEnd(space),
|
.addToStart(space)
|
||||||
),
|
.addToEnd(space),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -740,19 +740,15 @@ class DocumentComponent extends StatelessComponent {
|
||||||
|
|
||||||
class CategoryComponent extends StatelessComponent {
|
class CategoryComponent extends StatelessComponent {
|
||||||
final Category category;
|
final Category category;
|
||||||
final bool isSelected;
|
|
||||||
|
|
||||||
const CategoryComponent({
|
const CategoryComponent({
|
||||||
super.key,
|
super.key,
|
||||||
required this.category,
|
required this.category,
|
||||||
this.isSelected = false,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final backgroundTheme = FlutterFlowTheme.of(context).primaryBackground;
|
final backgroundTheme = FlutterFlowTheme.of(context).primaryBackground;
|
||||||
final textTheme = FlutterFlowTheme.of(context).primaryText;
|
|
||||||
final color = isSelected ? category.color.highlight : category.color;
|
|
||||||
return ColoredBox(
|
return ColoredBox(
|
||||||
color: backgroundTheme,
|
color: backgroundTheme,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
|
@ -762,7 +758,7 @@ class CategoryComponent extends StatelessComponent {
|
||||||
Container(
|
Container(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: color,
|
color: category.color,
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
),
|
),
|
||||||
child: Icon(
|
child: Icon(
|
||||||
|
@ -775,7 +771,7 @@ class CategoryComponent extends StatelessComponent {
|
||||||
Text(
|
Text(
|
||||||
category.title,
|
category.title,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: textTheme,
|
color: category.color,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
|
|
|
@ -46,15 +46,12 @@ class _AccessHistoryState extends State<AccessHistoryScreen> {
|
||||||
selectedTypeSubject.listen((value) {});
|
selectedTypeSubject.listen((value) {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_model = createModel(context, () => AcessHistoryPageModel());
|
_model = createModel(context, () => AcessHistoryPageModel());
|
||||||
_accessFuture = fetchAccessHistoryService();
|
_accessFuture = fetchAccessHistoryService();
|
||||||
|
|
||||||
|
|
||||||
_scrollController = ScrollController()
|
_scrollController = ScrollController()
|
||||||
..addListener(() {
|
..addListener(() {
|
||||||
if (_scrollController.position.atEdge &&
|
if (_scrollController.position.atEdge &&
|
||||||
|
|
|
@ -34,13 +34,20 @@ class LocalsRemoteDataSourceImpl implements LocalsRemoteDataSource {
|
||||||
try {
|
try {
|
||||||
final GetLocalsCall callback = FreAccessWSGlobal.getLocalsCall;
|
final GetLocalsCall callback = FreAccessWSGlobal.getLocalsCall;
|
||||||
var response = await callback.call();
|
var response = await callback.call();
|
||||||
if (response.jsonBody == null) return;
|
|
||||||
|
|
||||||
final bool? isError = response.jsonBody['error'];
|
final bool? isError = response.jsonBody['error'];
|
||||||
|
|
||||||
if (isError == true) {
|
if (isError == true) {
|
||||||
LocalUtil.handleError(context, response.jsonBody['error_msg']);
|
LocalUtil.handleError(context, response.jsonBody['error_msg']);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (response.jsonBody == null) {
|
||||||
|
// final String errorMsg = FFLocalizations.of(context).getVariableText(
|
||||||
|
// enText: 'Verify your connection',
|
||||||
|
// ptText: 'Verifique sua conexão',
|
||||||
|
// );
|
||||||
|
// await DialogUtil.error(context, errorMsg).whenComplete(() async => await selectLocal(context, response));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
final List<dynamic> locals = response.jsonBody['locais'] ?? [];
|
final List<dynamic> locals = response.jsonBody['locais'] ?? [];
|
||||||
final bool isEmpty = locals.isEmpty;
|
final bool isEmpty = locals.isEmpty;
|
||||||
|
|
|
@ -80,6 +80,7 @@ class LocalsRepositoryImpl implements LocalsRepository {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log('_handleLocal -> Local selected');
|
log('_handleLocal -> Local selected');
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -115,9 +115,6 @@ class LocalUtil {
|
||||||
.set(LocalsStorageKey.whatsapp.key, jsonBody['whatsapp'] ?? false);
|
.set(LocalsStorageKey.whatsapp.key, jsonBody['whatsapp'] ?? false);
|
||||||
await StorageHelper().set(
|
await StorageHelper().set(
|
||||||
LocalsStorageKey.provisional.key, jsonBody['provisional'] ?? false);
|
LocalsStorageKey.provisional.key, jsonBody['provisional'] ?? false);
|
||||||
await StorageHelper().set(LocalsStorageKey.vehicleAutoApproval.key,
|
|
||||||
jsonBody['vehicleAutoApproval'] ?? false);
|
|
||||||
|
|
||||||
await StorageHelper().set(
|
await StorageHelper().set(
|
||||||
LocalsStorageKey.pets.key,
|
LocalsStorageKey.pets.key,
|
||||||
jsonBody['pet'] ?? false,
|
jsonBody['pet'] ?? false,
|
||||||
|
@ -144,13 +141,6 @@ class LocalUtil {
|
||||||
jsonBody['petAmountRegister']?.toString().isEmpty ?? true
|
jsonBody['petAmountRegister']?.toString().isEmpty ?? true
|
||||||
? '0'
|
? '0'
|
||||||
: jsonBody['petAmountRegister'].toString());
|
: jsonBody['petAmountRegister'].toString());
|
||||||
|
|
||||||
await StorageHelper().set(
|
|
||||||
LocalsStorageKey.vehicleAmountRegister.key,
|
|
||||||
jsonBody['vehicleAmountRegister']?.toString().isEmpty ?? true
|
|
||||||
? '0'
|
|
||||||
: jsonBody['vehicleAmountRegister'].toString());
|
|
||||||
|
|
||||||
await StorageHelper().set(ProfileStorageKey.userName.key,
|
await StorageHelper().set(ProfileStorageKey.userName.key,
|
||||||
jsonBody['visitado']['VDO_NOME'] ?? '');
|
jsonBody['visitado']['VDO_NOME'] ?? '');
|
||||||
await StorageHelper().set(ProfileStorageKey.userEmail.key,
|
await StorageHelper().set(ProfileStorageKey.userEmail.key,
|
||||||
|
|
|
@ -17,6 +17,10 @@ abstract class MenuLocalDataSource {
|
||||||
|
|
||||||
Future<void> handleMenu(EnumMenuItem item, EnumDisplay display, MenuEntry opt,
|
Future<void> handleMenu(EnumMenuItem item, EnumDisplay display, MenuEntry opt,
|
||||||
List<MenuItem?> entries);
|
List<MenuItem?> entries);
|
||||||
|
|
||||||
|
Future<bool> processStartDate(String startDate, MenuEntry entry);
|
||||||
|
|
||||||
|
Future<bool> processExpirationDate(String expirationDate, MenuEntry entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
class MenuLocalDataSourceImpl implements MenuLocalDataSource {
|
class MenuLocalDataSourceImpl implements MenuLocalDataSource {
|
||||||
|
@ -88,4 +92,30 @@ class MenuLocalDataSourceImpl implements MenuLocalDataSource {
|
||||||
log('Error processing display for module ${opt.key}: $e');
|
log('Error processing display for module ${opt.key}: $e');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<bool> processStartDate(String startDate, MenuEntry opt) async {
|
||||||
|
try {
|
||||||
|
if (startDate.isEmpty) return true;
|
||||||
|
final start = DateTime.tryParse(startDate);
|
||||||
|
if (start == null) return false;
|
||||||
|
return DateTime.now().isAfter(start);
|
||||||
|
} catch (e) {
|
||||||
|
log('Error processing start date for module ${opt.key}: $e');
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<bool> processExpirationDate(
|
||||||
|
String expirationDate, MenuEntry opt) async {
|
||||||
|
try {
|
||||||
|
if (expirationDate.isEmpty) return false;
|
||||||
|
final expiration = DateTime.tryParse(expirationDate);
|
||||||
|
return expiration != null && DateTime.now().isAfter(expiration);
|
||||||
|
} catch (e) {
|
||||||
|
log('Error processing expiration date for module ${opt.key}: $e');
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@ import 'package:hub/features/menu/index.dart';
|
||||||
import 'package:hub/features/module/index.dart';
|
import 'package:hub/features/module/index.dart';
|
||||||
import 'package:hub/features/storage/index.dart';
|
import 'package:hub/features/storage/index.dart';
|
||||||
import 'package:hub/flutter_flow/custom_functions.dart';
|
import 'package:hub/flutter_flow/custom_functions.dart';
|
||||||
import 'package:hub/shared/utils/datetime_util.dart';
|
|
||||||
|
|
||||||
class MenuRepositoryImpl implements MenuRepository {
|
class MenuRepositoryImpl implements MenuRepository {
|
||||||
final MenuLocalDataSource menuDataSource = MenuLocalDataSourceImpl();
|
final MenuLocalDataSource menuDataSource = MenuLocalDataSourceImpl();
|
||||||
|
@ -26,9 +25,10 @@ class MenuRepositoryImpl implements MenuRepository {
|
||||||
final display = EnumDisplay.fromString(licenseMap['display']);
|
final display = EnumDisplay.fromString(licenseMap['display']);
|
||||||
final startDate = licenseMap['startDate'] ?? '';
|
final startDate = licenseMap['startDate'] ?? '';
|
||||||
final expirationDate = licenseMap['expirationDate'] ?? '';
|
final expirationDate = licenseMap['expirationDate'] ?? '';
|
||||||
final isStarted = await DateTimeUtil.processStartDate(startDate);
|
final isStarted =
|
||||||
|
await menuDataSource.processStartDate(startDate, entry);
|
||||||
final isExpired =
|
final isExpired =
|
||||||
await DateTimeUtil.processExpirationDate(expirationDate);
|
await menuDataSource.processExpirationDate(expirationDate, entry);
|
||||||
if (isStarted && !isExpired) {
|
if (isStarted && !isExpired) {
|
||||||
await menuDataSource.handleMenu(menuItem, display, entry, entries);
|
await menuDataSource.handleMenu(menuItem, display, entry, entries);
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,16 +76,6 @@ class MenuEntry implements BaseModule {
|
||||||
route: '/residentsOnThePropertyPage',
|
route: '/residentsOnThePropertyPage',
|
||||||
types: [MenuEntryType.Property],
|
types: [MenuEntryType.Property],
|
||||||
),
|
),
|
||||||
// MenuEntry(
|
|
||||||
// key: 'FRE-HUB-VEHICLES-MANAGER',
|
|
||||||
// icon: Icons.directions_car,
|
|
||||||
// name: FFLocalizations.of(navigatorKey.currentContext!).getVariableText(
|
|
||||||
// ptText: 'Veículos',
|
|
||||||
// enText: 'Vehicles',
|
|
||||||
// ),
|
|
||||||
// route: '/vehiclesOnThePropertyPage',
|
|
||||||
// types: [MenuEntryType.Property],
|
|
||||||
// ),
|
|
||||||
MenuEntry(
|
MenuEntry(
|
||||||
key: 'FRE-HUB-VEHICLES',
|
key: 'FRE-HUB-VEHICLES',
|
||||||
icon: Icons.directions_car,
|
icon: Icons.directions_car,
|
||||||
|
|
|
@ -94,7 +94,7 @@ class LicenseLocalDataSourceImpl implements LicenseLocalDataSource {
|
||||||
Future<bool> isNewVersion() async {
|
Future<bool> isNewVersion() async {
|
||||||
final String? reponse =
|
final String? reponse =
|
||||||
await StorageHelper().get(LocalsStorageKey.isNewVersion.key);
|
await StorageHelper().get(LocalsStorageKey.isNewVersion.key);
|
||||||
final bool isNewVersion = reponse.toBoolean;
|
final bool isNewVersion = reponse.toBoolean();
|
||||||
return isNewVersion;
|
return isNewVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,6 @@ enum LicenseKeys {
|
||||||
access('FRE-HUB-ACCESS'),
|
access('FRE-HUB-ACCESS'),
|
||||||
openedVisits('FRE-HUB-OPENED-VISITS'),
|
openedVisits('FRE-HUB-OPENED-VISITS'),
|
||||||
vehicles('FRE-HUB-VEHICLES'),
|
vehicles('FRE-HUB-VEHICLES'),
|
||||||
vehiclesManager('FRE-HUB-VEHICLES-MANAGER'),
|
|
||||||
residents('FRE-HUB-RESIDENTS'),
|
residents('FRE-HUB-RESIDENTS'),
|
||||||
about('FRE-HUB-ABOUT-SYSTEM'),
|
about('FRE-HUB-ABOUT-SYSTEM'),
|
||||||
pets('FRE-HUB-PETS'),
|
pets('FRE-HUB-PETS'),
|
||||||
|
@ -64,7 +63,7 @@ class License {
|
||||||
static Future<String> _precessWpp() async {
|
static Future<String> _precessWpp() async {
|
||||||
final bool whatsapp = await StorageHelper()
|
final bool whatsapp = await StorageHelper()
|
||||||
.get(LocalsStorageKey.whatsapp.key)
|
.get(LocalsStorageKey.whatsapp.key)
|
||||||
.then((v) => v.toBoolean);
|
.then((v) => v.toBoolean());
|
||||||
if (whatsapp)
|
if (whatsapp)
|
||||||
return ModuleStatus.active.key;
|
return ModuleStatus.active.key;
|
||||||
else
|
else
|
||||||
|
@ -74,7 +73,7 @@ class License {
|
||||||
static Future<String> _processProvisional() async {
|
static Future<String> _processProvisional() async {
|
||||||
final bool provisional = await StorageHelper()
|
final bool provisional = await StorageHelper()
|
||||||
.get(LocalsStorageKey.provisional.key)
|
.get(LocalsStorageKey.provisional.key)
|
||||||
.then((v) => v.toBoolean);
|
.then((v) => v.toBoolean());
|
||||||
if (provisional)
|
if (provisional)
|
||||||
return ModuleStatus.active.key;
|
return ModuleStatus.active.key;
|
||||||
else
|
else
|
||||||
|
@ -84,7 +83,7 @@ class License {
|
||||||
static Future<String> _processPets() async {
|
static Future<String> _processPets() async {
|
||||||
final bool pets = await StorageHelper()
|
final bool pets = await StorageHelper()
|
||||||
.get(LocalsStorageKey.pets.key)
|
.get(LocalsStorageKey.pets.key)
|
||||||
.then((v) => v.toBoolean);
|
.then((v) => v.toBoolean());
|
||||||
if (pets)
|
if (pets)
|
||||||
return ModuleStatus.active.key;
|
return ModuleStatus.active.key;
|
||||||
else
|
else
|
||||||
|
@ -164,13 +163,6 @@ class License {
|
||||||
startDate: '',
|
startDate: '',
|
||||||
quantity: 0,
|
quantity: 0,
|
||||||
),
|
),
|
||||||
Module(
|
|
||||||
key: LicenseKeys.vehicles.value,
|
|
||||||
display: ModuleStatus.inactive.key,
|
|
||||||
expirationDate: '',
|
|
||||||
startDate: '',
|
|
||||||
quantity: 0,
|
|
||||||
),
|
|
||||||
Module(
|
Module(
|
||||||
key: LicenseKeys.residents.value,
|
key: LicenseKeys.residents.value,
|
||||||
display: isNewVersionWithModule
|
display: isNewVersionWithModule
|
||||||
|
|
|
@ -34,9 +34,7 @@ enum LocalsStorageKey implements DatabaseStorageKey {
|
||||||
panic('fre_panic'),
|
panic('fre_panic'),
|
||||||
person('fre_person'),
|
person('fre_person'),
|
||||||
requestOSNotification('fre_requestOSnotification'),
|
requestOSNotification('fre_requestOSnotification'),
|
||||||
isNewVersion('fre_isNewVersion'),
|
isNewVersion('fre_isNewVersion');
|
||||||
vehicleAutoApproval('fre_vehicleAutoApproval'),
|
|
||||||
vehicleAmountRegister('fre_vehicleAmountRegister');
|
|
||||||
|
|
||||||
final String key;
|
final String key;
|
||||||
|
|
||||||
|
|
|
@ -529,7 +529,7 @@ void setAppLanguage(BuildContext context, String language) =>
|
||||||
void setDarkModeSetting(BuildContext context, ThemeMode themeMode) =>
|
void setDarkModeSetting(BuildContext context, ThemeMode themeMode) =>
|
||||||
App.of(context).setThemeMode(themeMode);
|
App.of(context).setThemeMode(themeMode);
|
||||||
|
|
||||||
void showSnackbarMessenger(
|
void showSnackbar(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
String message,
|
String message,
|
||||||
bool error, {
|
bool error, {
|
||||||
|
@ -537,47 +537,38 @@ void showSnackbarMessenger(
|
||||||
int duration = 4,
|
int duration = 4,
|
||||||
}) {
|
}) {
|
||||||
ScaffoldMessenger.of(context).hideCurrentSnackBar();
|
ScaffoldMessenger.of(context).hideCurrentSnackBar();
|
||||||
ScaffoldMessenger.of(context)
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
.showSnackBar(showSnackbar(context, message, error));
|
SnackBar(
|
||||||
}
|
content: Row(
|
||||||
|
children: [
|
||||||
SnackBar showSnackbar(
|
if (loading)
|
||||||
BuildContext context,
|
Padding(
|
||||||
String message,
|
padding: const EdgeInsetsDirectional.only(end: 10.0),
|
||||||
bool error, {
|
child: SizedBox(
|
||||||
bool loading = false,
|
height: 20,
|
||||||
int duration = 4,
|
width: 20,
|
||||||
}) {
|
child: CircularProgressIndicator(
|
||||||
return SnackBar(
|
color: FlutterFlowTheme.of(context).info,
|
||||||
content: Row(
|
),
|
||||||
children: [
|
|
||||||
if (loading)
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsetsDirectional.only(end: 10.0),
|
|
||||||
child: SizedBox(
|
|
||||||
height: 20,
|
|
||||||
width: 20,
|
|
||||||
child: CircularProgressIndicator(
|
|
||||||
color: FlutterFlowTheme.of(context).info,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
Text(
|
||||||
|
message,
|
||||||
|
style: TextStyle(
|
||||||
|
color: FlutterFlowTheme.of(context).info,
|
||||||
|
fontSize: LimitedFontSizeUtil.getBodyFontSize(context),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
Text(
|
],
|
||||||
message,
|
),
|
||||||
style: TextStyle(
|
duration: Duration(seconds: duration),
|
||||||
color: FlutterFlowTheme.of(context).info,
|
backgroundColor: error
|
||||||
fontSize: LimitedFontSizeUtil.getBodyFontSize(context),
|
? FlutterFlowTheme.of(context).error
|
||||||
),
|
: FlutterFlowTheme.of(context).success,
|
||||||
),
|
behavior: SnackBarBehavior.floating,
|
||||||
],
|
shape: RoundedRectangleBorder(
|
||||||
),
|
borderRadius: BorderRadius.circular(30),
|
||||||
duration: Duration(seconds: duration),
|
),
|
||||||
backgroundColor: error
|
|
||||||
? FlutterFlowTheme.of(context).error
|
|
||||||
: FlutterFlowTheme.of(context).success,
|
|
||||||
behavior: SnackBarBehavior.floating,
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(30),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -198,7 +198,7 @@ GoRouter createRouter(AppStateNotifier appStateNotifier) {
|
||||||
FFRoute(
|
FFRoute(
|
||||||
name: 'vehiclesOnThePropertyPage',
|
name: 'vehiclesOnThePropertyPage',
|
||||||
path: '/vehiclesOnThePropertyPage',
|
path: '/vehiclesOnThePropertyPage',
|
||||||
builder: (context, params) => const VehiclePage()),
|
builder: (context, params) => const VehicleOnTheProperty()),
|
||||||
FFRoute(
|
FFRoute(
|
||||||
name: 'receptionPage',
|
name: 'receptionPage',
|
||||||
path: '/receptionPage',
|
path: '/receptionPage',
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import 'dart:developer';
|
import 'dart:developer';
|
||||||
import 'dart:io';
|
|
||||||
|
|
||||||
import 'package:app_tracking_transparency/app_tracking_transparency.dart';
|
import 'package:app_tracking_transparency/app_tracking_transparency.dart';
|
||||||
import 'package:firebase_core/firebase_core.dart';
|
import 'package:firebase_core/firebase_core.dart';
|
||||||
|
@ -14,33 +13,23 @@ import 'package:hub/flutter_flow/flutter_flow_theme.dart';
|
||||||
import 'package:hub/flutter_flow/flutter_flow_util.dart';
|
import 'package:hub/flutter_flow/flutter_flow_util.dart';
|
||||||
import 'package:hub/flutter_flow/nav/nav.dart';
|
import 'package:hub/flutter_flow/nav/nav.dart';
|
||||||
|
|
||||||
Future<void> initializeBindings() async {
|
Future<void> initializeApp() async {
|
||||||
// await _initializeTracking();
|
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
await _initializeAppTrackingTransparency();
|
await _initializeTracking();
|
||||||
await StorageHelper().init();
|
await StorageHelper().init();
|
||||||
|
|
||||||
await _initializeFirebase();
|
await _initializeFirebase();
|
||||||
await _initializeNotificationService();
|
await _initializeNotificationService();
|
||||||
await _initializeUrlStrategy();
|
_initializeUrlStrategy();
|
||||||
await _initializeSystemSettings();
|
_initializeSystemSettings();
|
||||||
await _initializeFlutterFlow();
|
await _initializeFlutterFlow();
|
||||||
await _initializeNav();
|
await _initializeNav();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _initializeAppTrackingTransparency() async {
|
Future<void> _initializeTracking() async {
|
||||||
if (Platform.isIOS) {
|
log('Requesting tracking authorization...');
|
||||||
final status = await AppTrackingTransparency.trackingAuthorizationStatus;
|
await AppTrackingTransparency.requestTrackingAuthorization();
|
||||||
if (status == TrackingStatus.notDetermined) {
|
log('Tracking authorization requested');
|
||||||
await Future.delayed(const Duration(seconds: 2));
|
|
||||||
final request =
|
|
||||||
await AppTrackingTransparency.requestTrackingAuthorization();
|
|
||||||
if (request == TrackingStatus.authorized) {
|
|
||||||
log('Tracking authorized');
|
|
||||||
} else {
|
|
||||||
log('Tracking not authorized');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _initializeFirebase() async {
|
Future<void> _initializeFirebase() async {
|
||||||
|
@ -55,21 +44,19 @@ Future<void> _initializeNotificationService() async {
|
||||||
log('Notification Service initialized');
|
log('Notification Service initialized');
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _initializeUrlStrategy() async {
|
void _initializeUrlStrategy() {
|
||||||
print('Initializing URL Strategy...');
|
log('Initializing URL Strategy...');
|
||||||
setUrlStrategy(PathUrlStrategy());
|
setUrlStrategy(PathUrlStrategy());
|
||||||
log('URL Strategy initialized');
|
log('URL Strategy initialized');
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _initializeSystemSettings() async {
|
Future<void> _initializeSystemSettings() async {
|
||||||
print('Initializing System Settings...');
|
log('Initializing System Settings...');
|
||||||
|
|
||||||
await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
|
|
||||||
final crashlyticsInstance = FirebaseCrashlytics.instance;
|
final crashlyticsInstance = FirebaseCrashlytics.instance;
|
||||||
|
|
||||||
|
await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
|
||||||
if (kDebugMode) {
|
if (kDebugMode) {
|
||||||
print('Debug mode');
|
log('Debug mode');
|
||||||
await crashlyticsInstance.setCrashlyticsCollectionEnabled(false);
|
|
||||||
} else {
|
} else {
|
||||||
log('Release mode');
|
log('Release mode');
|
||||||
|
|
||||||
|
@ -85,22 +72,10 @@ Future<void> _initializeSystemSettings() async {
|
||||||
// }
|
// }
|
||||||
|
|
||||||
await crashlyticsInstance.setCrashlyticsCollectionEnabled(true);
|
await crashlyticsInstance.setCrashlyticsCollectionEnabled(true);
|
||||||
if (crashlyticsInstance.isCrashlyticsCollectionEnabled) {
|
// if (crashlyticsInstance.isCrashlyticsCollectionEnabled) {
|
||||||
// Configura o tratamento de erros não capturados
|
FlutterError.onError = crashlyticsInstance.recordFlutterError;
|
||||||
FlutterError.onError = crashlyticsInstance.recordFlutterError;
|
log('Crashlytics enabled');
|
||||||
|
// }
|
||||||
crashlyticsInstance.checkForUnsentReports().then((unsentReports) {
|
|
||||||
if (unsentReports) {
|
|
||||||
crashlyticsInstance.sendUnsentReports();
|
|
||||||
print('Existem relatórios de falhas não enviados.');
|
|
||||||
} else {
|
|
||||||
print('Todos os relatórios de falhas foram enviados.');
|
|
||||||
}
|
|
||||||
}).catchError((error) {
|
|
||||||
print('Erro ao verificar ou enviar relatórios não enviados: $error');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
print('Crashlytics enabled');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@ import 'dart:async';
|
||||||
import 'dart:developer';
|
import 'dart:developer';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:app_tracking_transparency/app_tracking_transparency.dart';
|
|
||||||
import 'package:firebase_crashlytics/firebase_crashlytics.dart';
|
import 'package:firebase_crashlytics/firebase_crashlytics.dart';
|
||||||
import 'package:firebase_messaging/firebase_messaging.dart';
|
import 'package:firebase_messaging/firebase_messaging.dart';
|
||||||
import 'package:flutter/gestures.dart';
|
import 'package:flutter/gestures.dart';
|
||||||
|
@ -32,7 +31,7 @@ class CustomScrollBehavior extends MaterialScrollBehavior {
|
||||||
}
|
}
|
||||||
|
|
||||||
void main() async {
|
void main() async {
|
||||||
await initializeBindings();
|
await initializeApp();
|
||||||
runApp(const ProviderScope(child: App()));
|
runApp(const ProviderScope(child: App()));
|
||||||
FirebaseMessaging.onBackgroundMessage(_backgroundHandlerMessage);
|
FirebaseMessaging.onBackgroundMessage(_backgroundHandlerMessage);
|
||||||
}
|
}
|
||||||
|
@ -148,7 +147,7 @@ class _AppState extends State<App> {
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
// FirebaseCrashlytics.instance.setCrashlyticsCollectionEnabled(true);
|
FirebaseCrashlytics.instance.setCrashlyticsCollectionEnabled(true);
|
||||||
_appStateNotifier = AppStateNotifier.instance;
|
_appStateNotifier = AppStateNotifier.instance;
|
||||||
_router = createRouter(_appStateNotifier);
|
_router = createRouter(_appStateNotifier);
|
||||||
Future.delayed(
|
Future.delayed(
|
||||||
|
|
|
@ -299,7 +299,7 @@ class _LiberationHistoryWidgetState extends State<LiberationHistoryWidget> {
|
||||||
)
|
)
|
||||||
.then((message) {
|
.then((message) {
|
||||||
if (message != null || message != '') {
|
if (message != null || message != '') {
|
||||||
showSnackbarMessenger(
|
showSnackbar(
|
||||||
context,
|
context,
|
||||||
FFLocalizations.of(context).getVariableText(
|
FFLocalizations.of(context).getVariableText(
|
||||||
enText: 'Successfully resolved visit',
|
enText: 'Successfully resolved visit',
|
||||||
|
@ -308,7 +308,7 @@ class _LiberationHistoryWidgetState extends State<LiberationHistoryWidget> {
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
showSnackbarMessenger(context, message, true);
|
showSnackbar(context, message, true);
|
||||||
}
|
}
|
||||||
}).whenComplete(() {
|
}).whenComplete(() {
|
||||||
safeSetState(() {
|
safeSetState(() {
|
||||||
|
|
|
@ -478,7 +478,7 @@ class PetsPageModel extends FlutterFlowModel<PetsPageWidget> {
|
||||||
context.pop(value);
|
context.pop(value);
|
||||||
|
|
||||||
if (value == false) {
|
if (value == false) {
|
||||||
showSnackbarMessenger(
|
showSnackbar(
|
||||||
context,
|
context,
|
||||||
FFLocalizations.of(context).getVariableText(
|
FFLocalizations.of(context).getVariableText(
|
||||||
ptText: 'Erro ao excluir pet',
|
ptText: 'Erro ao excluir pet',
|
||||||
|
@ -487,7 +487,7 @@ class PetsPageModel extends FlutterFlowModel<PetsPageWidget> {
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
} else if (value == true) {
|
} else if (value == true) {
|
||||||
showSnackbarMessenger(
|
showSnackbar(
|
||||||
context,
|
context,
|
||||||
FFLocalizations.of(context).getVariableText(
|
FFLocalizations.of(context).getVariableText(
|
||||||
enText: 'Success deleting pet',
|
enText: 'Success deleting pet',
|
||||||
|
@ -498,7 +498,7 @@ class PetsPageModel extends FlutterFlowModel<PetsPageWidget> {
|
||||||
}
|
}
|
||||||
}).catchError((err, stack) {
|
}).catchError((err, stack) {
|
||||||
context.pop();
|
context.pop();
|
||||||
showSnackbarMessenger(
|
showSnackbar(
|
||||||
context,
|
context,
|
||||||
FFLocalizations.of(context).getVariableText(
|
FFLocalizations.of(context).getVariableText(
|
||||||
enText: 'Error deleting pet',
|
enText: 'Error deleting pet',
|
||||||
|
|
|
@ -86,9 +86,9 @@ class _PetsPageWidgetState extends State<PetsPageWidget>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void onEditingChanged([bool? value]) {
|
void onEditingChanged(bool value) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_model.handleEditingChanged(value!);
|
_model.handleEditingChanged(value);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import 'package:awesome_notifications/awesome_notifications.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:google_fonts/google_fonts.dart';
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
|
|
||||||
|
|
|
@ -472,7 +472,7 @@ class ScheduleCompleteVisitPageModel
|
||||||
context.pop(value);
|
context.pop(value);
|
||||||
|
|
||||||
if (value == false) {
|
if (value == false) {
|
||||||
showSnackbarMessenger(
|
showSnackbar(
|
||||||
context,
|
context,
|
||||||
FFLocalizations.of(context).getVariableText(
|
FFLocalizations.of(context).getVariableText(
|
||||||
enText: 'Error blocking visit',
|
enText: 'Error blocking visit',
|
||||||
|
@ -481,7 +481,7 @@ class ScheduleCompleteVisitPageModel
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
} else if (value == true) {
|
} else if (value == true) {
|
||||||
showSnackbarMessenger(
|
showSnackbar(
|
||||||
context,
|
context,
|
||||||
FFLocalizations.of(context).getVariableText(
|
FFLocalizations.of(context).getVariableText(
|
||||||
enText: 'Success canceling visit',
|
enText: 'Success canceling visit',
|
||||||
|
@ -492,7 +492,7 @@ class ScheduleCompleteVisitPageModel
|
||||||
}
|
}
|
||||||
}).catchError((err, stack) {
|
}).catchError((err, stack) {
|
||||||
context.pop();
|
context.pop();
|
||||||
showSnackbarMessenger(
|
showSnackbar(
|
||||||
context,
|
context,
|
||||||
FFLocalizations.of(context).getVariableText(
|
FFLocalizations.of(context).getVariableText(
|
||||||
enText: 'Error blocking visit',
|
enText: 'Error blocking visit',
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
export 'vehicles_on_the_property.dart';
|
|
||||||
export 'vehicle_model.dart';
|
|
|
@ -1,246 +0,0 @@
|
||||||
part of 'vehicles_on_the_property.dart';
|
|
||||||
|
|
||||||
class VehicleHistoryScreen extends StatefulWidget {
|
|
||||||
final VehicleModel model;
|
|
||||||
const VehicleHistoryScreen(this.model, {super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<VehicleHistoryScreen> createState() => _VehicleHistoryScreenState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _VehicleHistoryScreenState extends State<VehicleHistoryScreen>
|
|
||||||
with Pageable {
|
|
||||||
final apiCall = FreAccessWSGlobal.getVehiclesByProperty;
|
|
||||||
int totalOwnerVehicles = 0;
|
|
||||||
final PagingController<int, dynamic> _pagingController =
|
|
||||||
PagingController<int, dynamic>(firstPageKey: 1);
|
|
||||||
bool _isSnackble = true;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
_pagingController.addPageRequestListener(
|
|
||||||
(int pageKey) => fetchPage(
|
|
||||||
dataProvider: () async {
|
|
||||||
final newItems = await apiCall.call(pageKey.toString());
|
|
||||||
if (newItems.jsonBody == null) return (false, null);
|
|
||||||
final List<dynamic> vehicles =
|
|
||||||
(newItems.jsonBody['vehicles'] as List<dynamic>?) ?? [];
|
|
||||||
|
|
||||||
safeSetState(() {
|
|
||||||
totalOwnerVehicles = newItems.jsonBody['total_owner_vehicles'] ?? 0;
|
|
||||||
});
|
|
||||||
|
|
||||||
return (vehicles.isNotEmpty, vehicles);
|
|
||||||
},
|
|
||||||
onDataUnavailable: (vehicles) {
|
|
||||||
setState(() {});
|
|
||||||
final bool isFirst = pageKey == 2;
|
|
||||||
if (!isFirst && _isSnackble) showNoMoreDataSnackBar(context);
|
|
||||||
|
|
||||||
_pagingController.appendLastPage(vehicles);
|
|
||||||
},
|
|
||||||
onDataAvailable: (vehicles) {
|
|
||||||
setState(() {});
|
|
||||||
_pagingController.appendPage(vehicles, pageKey + 1);
|
|
||||||
},
|
|
||||||
onFetchError: (e, s) {
|
|
||||||
DialogUtil.errorDefault(context);
|
|
||||||
LogUtil.requestAPIFailed(
|
|
||||||
"proccessRequest.php", "", "Consulta de Veículo", e, s);
|
|
||||||
setState(() {});
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
_pagingController.addStatusListener(_showError);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
_pagingController.dispose();
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _showError(PagingStatus status) async {
|
|
||||||
if (status == PagingStatus.subsequentPageError) {
|
|
||||||
final message = FFLocalizations.of(context).getVariableText(
|
|
||||||
enText: 'Something went wrong while fetching a new page.',
|
|
||||||
ptText: 'Algo deu errado ao buscar uma nova página.',
|
|
||||||
);
|
|
||||||
final retry = FFLocalizations.of(context).getVariableText(
|
|
||||||
enText: 'Retry',
|
|
||||||
ptText: 'Recarregar',
|
|
||||||
);
|
|
||||||
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(
|
|
||||||
content: Text(message),
|
|
||||||
action: SnackBarAction(
|
|
||||||
label: retry,
|
|
||||||
onPressed: () => _pagingController.retryLastFailedRequest(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Column(
|
|
||||||
children: [
|
|
||||||
_buildHeader(context),
|
|
||||||
_buildBody(context),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildHeader(BuildContext context) {
|
|
||||||
final bodyFontSize = LimitedFontSizeUtil.getBodyFontSize(context);
|
|
||||||
final headerTitle = FFLocalizations.of(context).getVariableText(
|
|
||||||
ptText: "Meus Veículos: ",
|
|
||||||
enText: "My Vehicles: ",
|
|
||||||
);
|
|
||||||
final totalRegisteredVehicles = widget.model.amountRegister;
|
|
||||||
|
|
||||||
return SizedBox(
|
|
||||||
height: 30,
|
|
||||||
child: Center(
|
|
||||||
child: Text(
|
|
||||||
(widget.model.amountRegister == '0' ||
|
|
||||||
widget.model.amountRegister == null)
|
|
||||||
? ''
|
|
||||||
: "$headerTitle $totalOwnerVehicles/$totalRegisteredVehicles",
|
|
||||||
textAlign: TextAlign.right,
|
|
||||||
style: TextStyle(
|
|
||||||
fontFamily: 'Nunito',
|
|
||||||
fontSize: bodyFontSize,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Expanded _buildBody(BuildContext context) {
|
|
||||||
final noDataFound = FFLocalizations.of(context).getVariableText(
|
|
||||||
ptText: "Nenhum veículo encontrado!",
|
|
||||||
enText: "No vehicle found",
|
|
||||||
);
|
|
||||||
return buildPaginatedListView<int, dynamic>(
|
|
||||||
noDataFound,
|
|
||||||
_pagingController,
|
|
||||||
_generateItems,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _generateItems(
|
|
||||||
BuildContext context,
|
|
||||||
dynamic item,
|
|
||||||
int index,
|
|
||||||
) {
|
|
||||||
log('item: $item');
|
|
||||||
final bool? isOwner = item['isOwnerVehicle'];
|
|
||||||
final IconData iconData =
|
|
||||||
isOwner == true ? Symbols.garage : Symbols.directions_car;
|
|
||||||
|
|
||||||
final FreCardIcon? cardIcon = isOwner != null
|
|
||||||
? FreCardIcon(
|
|
||||||
height: 50,
|
|
||||||
width: 100,
|
|
||||||
icon: Icon(iconData, size: 80, opticalSize: 10),
|
|
||||||
)
|
|
||||||
: null;
|
|
||||||
|
|
||||||
final String? tag = item['tag'];
|
|
||||||
final bool containTag = tag.isNotNullAndEmpty;
|
|
||||||
final Map<String, String> labelsHashMap =
|
|
||||||
_generateLabelsHashMap(context, item, tag, containTag);
|
|
||||||
|
|
||||||
final List<Map<String, Color>> statusHashMapList =
|
|
||||||
_generateStatusHashMapList(item);
|
|
||||||
|
|
||||||
Future<void> onTapCardItemAction() async {
|
|
||||||
await _handleCardItemTap(context, cardIcon, item);
|
|
||||||
}
|
|
||||||
|
|
||||||
final statusLinkedHashMap = statusHashMapList
|
|
||||||
.map((map) => LinkedHashMap<String, Color>.from(map))
|
|
||||||
.toList();
|
|
||||||
final length = statusLinkedHashMap.expand((e) => [e.length]);
|
|
||||||
final double itemWidthFactor = length == 1 ? 0.25 : 0.50;
|
|
||||||
|
|
||||||
return CardItemTemplateComponentWidget(
|
|
||||||
icon: cardIcon,
|
|
||||||
labelsHashMap: labelsHashMap,
|
|
||||||
statusHashMap: statusHashMapList,
|
|
||||||
onTapCardItemAction: onTapCardItemAction,
|
|
||||||
itemWidthFactor: itemWidthFactor,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, String> _generateLabelsHashMap(
|
|
||||||
BuildContext context,
|
|
||||||
Map<String, dynamic> item,
|
|
||||||
String? tag,
|
|
||||||
bool containTag,
|
|
||||||
) {
|
|
||||||
final localization = FFLocalizations.of(context);
|
|
||||||
return {
|
|
||||||
'${localization.getVariableText(ptText: "Placa", enText: "License Plate")}:':
|
|
||||||
item['licensePlate'] ?? '',
|
|
||||||
'${localization.getVariableText(ptText: "Modelo", enText: "Model")}:':
|
|
||||||
item['model'] ?? '',
|
|
||||||
'${localization.getVariableText(ptText: "Proprietário", enText: "Owner")}:':
|
|
||||||
item['personName'] ?? '',
|
|
||||||
if (containTag)
|
|
||||||
'${localization.getVariableText(ptText: "Tag", enText: "Tag")}:':
|
|
||||||
tag ?? '',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Map<String, Color>> _generateStatusHashMapList(
|
|
||||||
Map<String, dynamic> item) {
|
|
||||||
final statusHashMap = widget.model.generateStatusColorMap(item, false);
|
|
||||||
return statusHashMap != null ? [statusHashMap] : [];
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _handleCardItemTap(
|
|
||||||
BuildContext context,
|
|
||||||
FreCardIcon? cardIcon,
|
|
||||||
Map<String, dynamic> item,
|
|
||||||
) async {
|
|
||||||
try {
|
|
||||||
final dialogContent = widget.model.buildVehicleDetails(
|
|
||||||
icon: cardIcon,
|
|
||||||
item: item,
|
|
||||||
context: context,
|
|
||||||
model: widget.model,
|
|
||||||
);
|
|
||||||
|
|
||||||
await showDialog<bool>(
|
|
||||||
useSafeArea: true,
|
|
||||||
context: context,
|
|
||||||
builder: (context) => Dialog(
|
|
||||||
alignment: Alignment.center,
|
|
||||||
child: dialogContent,
|
|
||||||
),
|
|
||||||
) //
|
|
||||||
.then((response) async {
|
|
||||||
if (response == true) {
|
|
||||||
_isSnackble = false;
|
|
||||||
_pagingController.refresh();
|
|
||||||
} else {
|
|
||||||
_isSnackble = true;
|
|
||||||
}
|
|
||||||
}) //
|
|
||||||
.whenComplete(() {});
|
|
||||||
} catch (e, s) {
|
|
||||||
DialogUtil.errorDefault(context);
|
|
||||||
LogUtil.requestAPIFailed(
|
|
||||||
"proccessRequest.php", "", "Consulta de Veículos", e, s);
|
|
||||||
safeSetState(() {
|
|
||||||
// _hasData = false;
|
|
||||||
// _loading = false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,558 +1,54 @@
|
||||||
import 'dart:developer';
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:hub/components/templates_components/card_item_template_component/card_item_template_component_widget.dart';
|
|
||||||
import 'package:hub/components/templates_components/details_component/details_component_widget.dart';
|
import 'package:hub/components/templates_components/details_component/details_component_widget.dart';
|
||||||
import 'package:hub/features/backend/index.dart';
|
import 'package:hub/flutter_flow/flutter_flow_model.dart';
|
||||||
import 'package:hub/features/storage/index.dart';
|
import 'package:hub/flutter_flow/internationalization.dart';
|
||||||
import 'package:hub/flutter_flow/index.dart';
|
|
||||||
import 'package:hub/pages/vehicles_on_the_property/vehicles_on_the_property.dart';
|
import 'package:hub/pages/vehicles_on_the_property/vehicles_on_the_property.dart';
|
||||||
import 'package:hub/shared/extensions.dart';
|
|
||||||
import 'package:hub/shared/utils.dart';
|
|
||||||
|
|
||||||
/// [VehicleModel] is a class that contains the business logic of the vehicle page.
|
class VehicleModel extends FlutterFlowModel<VehicleOnTheProperty> {
|
||||||
class VehicleModel extends FlutterFlowModel<VehiclePage>
|
|
||||||
with
|
|
||||||
_BaseVehiclePage,
|
|
||||||
_VehicleHistoryScreenModel,
|
|
||||||
_VehicleRegisterScreenModel,
|
|
||||||
_VehicleUpdateScreenModel {
|
|
||||||
/// [VehicleModel] is a singleton class that contains the business logic of the vehicle page.
|
|
||||||
static VehicleModel? _instance = VehicleModel._internal();
|
static VehicleModel? _instance = VehicleModel._internal();
|
||||||
VehicleModel._internal();
|
VehicleModel._internal();
|
||||||
factory VehicleModel() => _instance ?? VehicleModel._internal();
|
factory VehicleModel() => _instance ?? VehicleModel._internal();
|
||||||
static void resetInstance() => _instance = null;
|
static void resetInstance() => _instance = null;
|
||||||
|
|
||||||
final GlobalKey<FormState> registerFormKey = GlobalKey<FormState>();
|
dynamic item;
|
||||||
final GlobalKey<FormState> updateFormKey = GlobalKey<FormState>();
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState(BuildContext context) {
|
void initState(BuildContext context) {
|
||||||
log('VehicleModel -> initState');
|
|
||||||
resetInstance();
|
resetInstance();
|
||||||
|
|
||||||
initAsync();
|
initAsync();
|
||||||
initializeControllers(context);
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
|
||||||
amountRegister = '0';
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void initializeControllers(BuildContext context) {
|
|
||||||
tabBarController = TabController(
|
|
||||||
vsync: Navigator.of(context),
|
|
||||||
length: 2,
|
|
||||||
);
|
|
||||||
|
|
||||||
textFieldFocusLicensePlate = FocusNode();
|
|
||||||
textFieldControllerLicensePlate = TextEditingController();
|
|
||||||
|
|
||||||
textFieldFocusColor = FocusNode();
|
|
||||||
textFieldControllerColor = TextEditingController();
|
|
||||||
|
|
||||||
textFieldFocusModel = FocusNode();
|
|
||||||
textFieldControllerModel = TextEditingController();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {}
|
||||||
disposeControllers();
|
|
||||||
}
|
|
||||||
|
|
||||||
void disposeControllers() {
|
Future<void> initAsync() async {}
|
||||||
tabBarController.dispose();
|
|
||||||
textFieldFocusLicensePlate!.dispose();
|
|
||||||
textFieldControllerLicensePlate!.dispose();
|
|
||||||
textFieldFocusColor!.dispose();
|
|
||||||
textFieldControllerColor!.dispose();
|
|
||||||
textFieldFocusModel!.dispose();
|
|
||||||
textFieldControllerModel!.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> initAsync() async {
|
Widget buildVehicleDetails({
|
||||||
amountRegister =
|
|
||||||
await StorageHelper().get(LocalsStorageKey.vehicleAmountRegister.key);
|
|
||||||
autoApproval =
|
|
||||||
await StorageHelper().get(LocalsStorageKey.vehicleAutoApproval.key);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isFormValid(BuildContext context, GlobalKey<FormState> formKey) {
|
|
||||||
if (formKey.currentState == null) return false;
|
|
||||||
return formKey.currentState!.validate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// [_BaseVehiclePage] is a mixin that contains the base logic of the vehicle page.
|
|
||||||
mixin class _BaseVehiclePage {
|
|
||||||
int count = 0;
|
|
||||||
late final TabController tabBarController;
|
|
||||||
// dynamic item;
|
|
||||||
late int vehicleId;
|
|
||||||
BuildContext context = navigatorKey.currentContext!;
|
|
||||||
bool isEditing = false;
|
|
||||||
ApiCallResponse? vehicleResponse;
|
|
||||||
String? amountRegister = '0';
|
|
||||||
late final String? autoApproval;
|
|
||||||
|
|
||||||
VoidCallback? onUpdateVehicle;
|
|
||||||
VoidCallback? onRegisterVehicle;
|
|
||||||
VoidCallback? safeSetState;
|
|
||||||
|
|
||||||
FocusNode? textFieldFocusLicensePlate;
|
|
||||||
TextEditingController? textFieldControllerLicensePlate;
|
|
||||||
String? textControllerLicensePlateValidator(
|
|
||||||
BuildContext context, String? value) {
|
|
||||||
final validationMessage = validateField(
|
|
||||||
context, value, 'Placa é obrigatória', 'License Plate is required');
|
|
||||||
if (validationMessage != null) return validationMessage;
|
|
||||||
|
|
||||||
final brazilianPlateRegex = RegExp(r'^[A-Z]{3}\d{4}$');
|
|
||||||
final mercosurPlateRegex = RegExp(r'^[A-Z]{3}\d[A-Z0-9]\d{2}$');
|
|
||||||
|
|
||||||
if (!brazilianPlateRegex.hasMatch(value!) &&
|
|
||||||
!mercosurPlateRegex.hasMatch(value)) {
|
|
||||||
return FFLocalizations.of(context).getVariableText(
|
|
||||||
ptText: 'Placa inválida',
|
|
||||||
enText: 'Invalid license plate',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
FocusNode? textFieldFocusColor;
|
|
||||||
TextEditingController? textFieldControllerColor;
|
|
||||||
String? textControllerColorValidator(BuildContext contexnt, String? value) {
|
|
||||||
return validateField(
|
|
||||||
context, value, 'Cor é obrigatória', 'Color is required');
|
|
||||||
}
|
|
||||||
|
|
||||||
FocusNode? textFieldFocusModel;
|
|
||||||
TextEditingController? textFieldControllerModel;
|
|
||||||
String? textControllerModelValidator(BuildContext contexnt, String? value) {
|
|
||||||
return validateField(
|
|
||||||
context, value, 'Modelo é obrigatório', 'Model is required');
|
|
||||||
}
|
|
||||||
|
|
||||||
String? validateField(
|
|
||||||
BuildContext context, String? value, String ptText, String enText) {
|
|
||||||
if (value == null || value.isEmpty) {
|
|
||||||
return FFLocalizations.of(context).getVariableText(
|
|
||||||
ptText: ptText,
|
|
||||||
enText: enText,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> switchTab(int index) async {
|
|
||||||
tabBarController.animateTo(index);
|
|
||||||
if (index == 0) await handleEditingChanged(false);
|
|
||||||
safeSetState?.call();
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> clearFields() async {
|
|
||||||
textFieldControllerLicensePlate = TextEditingController(text: '');
|
|
||||||
textFieldControllerColor = TextEditingController(text: '');
|
|
||||||
textFieldControllerModel = TextEditingController(text: '');
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> handleEditingChanged(bool editing) async {
|
|
||||||
isEditing = editing;
|
|
||||||
await clearFields();
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> setEditForm(dynamic item) async {
|
|
||||||
if (item != null) {
|
|
||||||
log('vehicleId: ${item['vehicleId']}');
|
|
||||||
vehicleId = item['vehicleId'];
|
|
||||||
|
|
||||||
textFieldControllerLicensePlate = TextEditingController(
|
|
||||||
text: item != null ? item['licensePlate'] ?? '' : '');
|
|
||||||
textFieldControllerColor =
|
|
||||||
TextEditingController(text: item != null ? item['color'] ?? '' : '');
|
|
||||||
textFieldControllerModel =
|
|
||||||
TextEditingController(text: item != null ? item['model'] ?? '' : '');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> handleVehicleResponse(ApiCallResponse response,
|
|
||||||
String successMessage, String errorMessage) async {
|
|
||||||
if (response.jsonBody['error'] == false) {
|
|
||||||
await DialogUtil.success(context, successMessage).then((_) async {
|
|
||||||
await switchTab(0);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
String errorMsg;
|
|
||||||
try {
|
|
||||||
errorMsg = response.jsonBody['error_msg'];
|
|
||||||
} catch (e) {
|
|
||||||
errorMsg = errorMessage;
|
|
||||||
}
|
|
||||||
await DialogUtil.error(context, errorMsg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// [_VehicleRegisterScreenModel] is a mixin that contains the business logic of the vehicle register page.
|
|
||||||
mixin _VehicleRegisterScreenModel on _BaseVehiclePage {
|
|
||||||
Future<void> registerVehicle() async {
|
|
||||||
final response = await FreAccessWSGlobal.registerVehicle.call(
|
|
||||||
licensePlate: textFieldControllerLicensePlate!.text,
|
|
||||||
color: textFieldControllerColor!.text,
|
|
||||||
model: textFieldControllerModel!.text,
|
|
||||||
);
|
|
||||||
await handleVehicleResponse(
|
|
||||||
response,
|
|
||||||
FFLocalizations.of(context).getVariableText(
|
|
||||||
ptText: 'Veículo cadastrado com sucesso',
|
|
||||||
enText: 'Vehicle registered successfully',
|
|
||||||
),
|
|
||||||
FFLocalizations.of(context).getVariableText(
|
|
||||||
ptText: 'Erro ao cadastrar veículo',
|
|
||||||
enText: 'Error registering vehicle',
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// [_VehicleUpdateScreenModel] is a mixin that contains the business logic of the vehicle update page.
|
|
||||||
mixin _VehicleUpdateScreenModel on _BaseVehiclePage {
|
|
||||||
Future<void> updateVehicle() async {
|
|
||||||
final response = await FreAccessWSGlobal.updateVehicle.call(
|
|
||||||
licensePlate: textFieldControllerLicensePlate!.text,
|
|
||||||
color: textFieldControllerColor!.text,
|
|
||||||
model: textFieldControllerModel!.text,
|
|
||||||
vehicleId: vehicleId,
|
|
||||||
);
|
|
||||||
await handleVehicleResponse(
|
|
||||||
response,
|
|
||||||
FFLocalizations.of(context).getVariableText(
|
|
||||||
ptText: 'Veículo atualizado com sucesso',
|
|
||||||
enText: 'Vehicle updated successfully',
|
|
||||||
),
|
|
||||||
FFLocalizations.of(context).getVariableText(
|
|
||||||
ptText: 'Erro ao atualizar veículo',
|
|
||||||
enText: 'Error updating vehicle',
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// [_VehicleHistoryScreenModel] is a mixin that contains the business logic of the vehicle history page.
|
|
||||||
mixin _VehicleHistoryScreenModel on _BaseVehiclePage {
|
|
||||||
Map<String, Color>? generateStatusColorMap(dynamic uItem, bool isDetail) {
|
|
||||||
if (autoApproval.toBoolean == true) return null;
|
|
||||||
final theme = FlutterFlowTheme.of(context);
|
|
||||||
final localization = FFLocalizations.of(context);
|
|
||||||
|
|
||||||
final status = uItem['status'];
|
|
||||||
final isOwner = uItem['isOwnerVehicle'];
|
|
||||||
|
|
||||||
if (isOwner == null && status == null) return null;
|
|
||||||
|
|
||||||
String byLanguage(String en, String pt) =>
|
|
||||||
localization.getVariableText(enText: en, ptText: pt);
|
|
||||||
|
|
||||||
final vehicleStatusMap = {
|
|
||||||
"ATI": {
|
|
||||||
"text": byLanguage('Active', 'Ativo'),
|
|
||||||
"color": theme.success,
|
|
||||||
},
|
|
||||||
"INA": {
|
|
||||||
"text": byLanguage('Inactive', 'Inativo'),
|
|
||||||
"color": theme.accent2,
|
|
||||||
},
|
|
||||||
"APR_CREATE": {
|
|
||||||
"text": byLanguage('Awaiting Creation', 'Aguardando Criação'),
|
|
||||||
"color": theme.success,
|
|
||||||
},
|
|
||||||
"APR_DELETE": {
|
|
||||||
"text": byLanguage('Awaiting Deletion', 'Aguardando Exclusão'),
|
|
||||||
"color": theme.error,
|
|
||||||
},
|
|
||||||
"APR_UPDATE": {
|
|
||||||
"text": byLanguage('Awaiting Update', 'Aguardando Atualização'),
|
|
||||||
"color": theme.accent2,
|
|
||||||
},
|
|
||||||
"AGU_CHANGE": {
|
|
||||||
"text": byLanguage('Awaiting Change', 'Aguardando Alteração'),
|
|
||||||
"color": theme.warning,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
if (vehicleStatusMap.containsKey(status)) {
|
|
||||||
final statusMap = {
|
|
||||||
vehicleStatusMap[status]!['text'] as String:
|
|
||||||
vehicleStatusMap[status]!['color'] as Color,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!isDetail && isOwner && (status != 'ATI' && status != 'INA')) {
|
|
||||||
statusMap[byLanguage('My Vehicle', 'Meu Veículo')] = theme.accent4;
|
|
||||||
}
|
|
||||||
|
|
||||||
return statusMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
List<FFButtonWidget> generateActionButtons(dynamic item) {
|
|
||||||
final Color iconButtonColor = FlutterFlowTheme.of(context).primaryText;
|
|
||||||
final FFButtonOptions buttonOptions = FFButtonOptions(
|
|
||||||
height: 40,
|
|
||||||
color: FlutterFlowTheme.of(context).primaryBackground,
|
|
||||||
elevation: 0,
|
|
||||||
textStyle: TextStyle(
|
|
||||||
color: FlutterFlowTheme.of(context).primaryText,
|
|
||||||
fontSize: LimitedFontSizeUtil.getNoResizeFont(context, 15),
|
|
||||||
),
|
|
||||||
splashColor: FlutterFlowTheme.of(context).success,
|
|
||||||
borderSide: BorderSide(
|
|
||||||
color: FlutterFlowTheme.of(context).primaryBackground,
|
|
||||||
width: 1,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
if (item['status'] == null) return [];
|
|
||||||
|
|
||||||
final updateText = FFLocalizations.of(context)
|
|
||||||
.getVariableText(ptText: 'Editar', enText: 'Edit');
|
|
||||||
final updateIcon = Icon(Icons.edit, color: iconButtonColor);
|
|
||||||
Future updateOnPressed() async {
|
|
||||||
context.pop();
|
|
||||||
isEditing = true;
|
|
||||||
|
|
||||||
await switchTab(1);
|
|
||||||
await setEditForm(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
final cancelText = FFLocalizations.of(context)
|
|
||||||
.getVariableText(ptText: 'Cancelar', enText: 'Cancel');
|
|
||||||
final cancelIcon = Icon(Icons.close, color: iconButtonColor);
|
|
||||||
Future cancelOnPressed() async {
|
|
||||||
showAlertDialog(
|
|
||||||
context,
|
|
||||||
FFLocalizations.of(context).getVariableText(
|
|
||||||
ptText: 'Cancelar Solicitação',
|
|
||||||
enText: 'Cancel Request',
|
|
||||||
),
|
|
||||||
FFLocalizations.of(context).getVariableText(
|
|
||||||
ptText: 'Você tem certeza que deseja cancelar essa solicitação?',
|
|
||||||
enText: 'Are you sure you want to delete this request?',
|
|
||||||
),
|
|
||||||
() async => await processCancelRequest(item['status'], item));
|
|
||||||
}
|
|
||||||
|
|
||||||
final deleteText = FFLocalizations.of(context)
|
|
||||||
.getVariableText(ptText: 'Excluir', enText: 'Delete');
|
|
||||||
final deleteIcon = Icon(Icons.delete, color: iconButtonColor);
|
|
||||||
Future deleteOnPressed() async {
|
|
||||||
showAlertDialog(
|
|
||||||
context,
|
|
||||||
FFLocalizations.of(context).getVariableText(
|
|
||||||
ptText: 'Excluir Veículo',
|
|
||||||
enText: 'Delete Vehicle',
|
|
||||||
),
|
|
||||||
FFLocalizations.of(context).getVariableText(
|
|
||||||
ptText: 'Você tem certeza que deseja excluir esse veículo?',
|
|
||||||
enText: 'Are you sure you want to delete this vehicle?',
|
|
||||||
),
|
|
||||||
() async => processDeleteRequest(item),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
final bool containStatus = item['status'] == null;
|
|
||||||
final bool isOwnerVehicle = item['isOwnerVehicle'];
|
|
||||||
final bool isAGU = item['status'].contains('AGU');
|
|
||||||
final bool isAPR = item['status'].contains('APR');
|
|
||||||
final bool isATI = item['status'].contains('ATI');
|
|
||||||
|
|
||||||
if (containStatus)
|
|
||||||
return [
|
|
||||||
FFButtonWidget(
|
|
||||||
text: deleteText,
|
|
||||||
icon: deleteIcon,
|
|
||||||
onPressed: deleteOnPressed,
|
|
||||||
options: buttonOptions,
|
|
||||||
),
|
|
||||||
];
|
|
||||||
|
|
||||||
return [
|
|
||||||
if (isAGU && isOwnerVehicle)
|
|
||||||
FFButtonWidget(
|
|
||||||
text: updateText,
|
|
||||||
icon: updateIcon,
|
|
||||||
onPressed: updateOnPressed,
|
|
||||||
options: buttonOptions,
|
|
||||||
),
|
|
||||||
if ((isAPR || isAGU) && (isOwnerVehicle))
|
|
||||||
FFButtonWidget(
|
|
||||||
text: cancelText,
|
|
||||||
icon: cancelIcon,
|
|
||||||
onPressed: cancelOnPressed,
|
|
||||||
options: buttonOptions,
|
|
||||||
),
|
|
||||||
if (isATI && isOwnerVehicle)
|
|
||||||
FFButtonWidget(
|
|
||||||
text: deleteText,
|
|
||||||
icon: deleteIcon,
|
|
||||||
onPressed: deleteOnPressed,
|
|
||||||
options: buttonOptions,
|
|
||||||
),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<bool> processDeleteRequest(dynamic item) async {
|
|
||||||
log('processDeleteRequest -> item[$item]');
|
|
||||||
bool result = await FreAccessWSGlobal.deleteVehicle
|
|
||||||
.call(
|
|
||||||
vehicleId: item['vehicleId'],
|
|
||||||
licensePlate: item['licensePlate'],
|
|
||||||
model: item['model'],
|
|
||||||
color: item['color'],
|
|
||||||
)
|
|
||||||
.then((value) {
|
|
||||||
// ignore: unrelated_type_equality_checks
|
|
||||||
if (value.jsonBody['error'] == true) {
|
|
||||||
final String errorMsg = value.jsonBody['error_msg'];
|
|
||||||
showSnackbarMessenger(
|
|
||||||
context,
|
|
||||||
FFLocalizations.of(context).getVariableText(
|
|
||||||
ptText: errorMsg,
|
|
||||||
enText: 'Error deleting vehicle',
|
|
||||||
),
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
return false;
|
|
||||||
// ignore: unrelated_type_equality_checks
|
|
||||||
}
|
|
||||||
showSnackbarMessenger(
|
|
||||||
context,
|
|
||||||
FFLocalizations.of(context).getVariableText(
|
|
||||||
enText: 'Success deleting vehicle',
|
|
||||||
ptText: 'Succeso ao excluir veículo',
|
|
||||||
),
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
return true;
|
|
||||||
}) //
|
|
||||||
.catchError((err, stack) {
|
|
||||||
showSnackbarMessenger(
|
|
||||||
context,
|
|
||||||
FFLocalizations.of(context).getVariableText(
|
|
||||||
enText: 'Error deleting vehicle',
|
|
||||||
ptText: 'Erro ao excluir veículo',
|
|
||||||
),
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
context.pop(result);
|
|
||||||
context.pop(result);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<bool> processCancelRequest(String status, dynamic item) async {
|
|
||||||
try {
|
|
||||||
final ApiCallResponse value;
|
|
||||||
switch (status) {
|
|
||||||
case 'APR_CREATE':
|
|
||||||
value = await processCancelDeleteRequest(item);
|
|
||||||
break;
|
|
||||||
case 'AGU_CHANGE':
|
|
||||||
value = await processCancelUpdateRequest(item);
|
|
||||||
break;
|
|
||||||
case 'APR_DELETE':
|
|
||||||
value = await processCancelCreateRequest(item);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw ArgumentError('Status inválido: $status');
|
|
||||||
}
|
|
||||||
|
|
||||||
final bool isError = value.jsonBody['error'] == true;
|
|
||||||
final String message = FFLocalizations.of(context).getVariableText(
|
|
||||||
ptText: value.jsonBody['error_msg'] ?? 'Erro ao cancelar solicitação',
|
|
||||||
enText:
|
|
||||||
isError ? 'Error canceling request' : 'Success canceling request',
|
|
||||||
);
|
|
||||||
showSnackbarMessenger(context, message, isError);
|
|
||||||
context.pop(!isError);
|
|
||||||
context.pop(!isError);
|
|
||||||
return !isError;
|
|
||||||
} catch (err) {
|
|
||||||
final String errorMessage = FFLocalizations.of(context).getVariableText(
|
|
||||||
ptText: 'Erro ao cancelar solicitação',
|
|
||||||
enText: 'Error canceling request',
|
|
||||||
);
|
|
||||||
showSnackbarMessenger(context, errorMessage, true);
|
|
||||||
context.pop(false);
|
|
||||||
context.pop(false);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<ApiCallResponse> processCancelDeleteRequest(dynamic item) async {
|
|
||||||
return await FreAccessWSGlobal.deleteVehicle.call(
|
|
||||||
vehicleId: item['vehicleId'],
|
|
||||||
licensePlate: item['licensePlate'],
|
|
||||||
model: item['model'],
|
|
||||||
color: item['color'],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<ApiCallResponse> processCancelUpdateRequest(dynamic item) async {
|
|
||||||
return await FreAccessWSGlobal.deleteVehicle.call(
|
|
||||||
vehicleId: item['vehicleId'],
|
|
||||||
licensePlate: item['licensePlate'],
|
|
||||||
model: item['model'],
|
|
||||||
color: item['color'],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<ApiCallResponse> processCancelCreateRequest(dynamic item) async {
|
|
||||||
return await FreAccessWSGlobal.cancelDelete.call(
|
|
||||||
vehicleId: item['vehicleId'],
|
|
||||||
licensePlate: item['licensePlate'],
|
|
||||||
model: item['model'],
|
|
||||||
color: item['color'],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, String> generateLabelsHashMap(dynamic item) {
|
|
||||||
return {
|
|
||||||
if (item['model'] != null && item['model'] != '')
|
|
||||||
'${FFLocalizations.of(context).getVariableText(ptText: "Modelo", enText: "Model")}:':
|
|
||||||
item['model'].toString().toUpperCase(),
|
|
||||||
if (item['licensePlate'] != null && item['licensePlate'] != '')
|
|
||||||
'${FFLocalizations.of(context).getVariableText(ptText: "Placa", enText: "License Plate")}:':
|
|
||||||
item['licensePlate'].toString().toUpperCase(),
|
|
||||||
if (item['color'] != null && item['color'] != '')
|
|
||||||
'${FFLocalizations.of(context).getVariableText(ptText: "Cor", enText: "Color")}:':
|
|
||||||
item['color'].toString().toUpperCase(),
|
|
||||||
if (item['personName'] != null && item['personName'] != '')
|
|
||||||
'${FFLocalizations.of(context).getVariableText(ptText: "Proprietário", enText: "Owner")}:':
|
|
||||||
item['personName'].toString().toUpperCase(),
|
|
||||||
if (item['tag'] != null && item['tag'] != '')
|
|
||||||
'${FFLocalizations.of(context).getVariableText(ptText: "Tag", enText: "Tag")}:':
|
|
||||||
item['tag'].toString().toUpperCase(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
DetailsComponentWidget buildVehicleDetails({
|
|
||||||
required dynamic item,
|
required dynamic item,
|
||||||
required BuildContext context,
|
required BuildContext context,
|
||||||
required VehicleModel model,
|
required VehicleModel model,
|
||||||
required FreCardIcon? icon,
|
|
||||||
}) {
|
}) {
|
||||||
final status = generateStatusColorMap(item, true);
|
|
||||||
final buttons = generateActionButtons(item);
|
|
||||||
final labels = generateLabelsHashMap(item);
|
|
||||||
return DetailsComponentWidget(
|
return DetailsComponentWidget(
|
||||||
icon: icon,
|
buttons: [],
|
||||||
buttons: buttons,
|
labelsHashMap: Map<String, String>.from({
|
||||||
labelsHashMap: labels,
|
if (item['model'] != null && item['model'] != '')
|
||||||
statusHashMap: [status],
|
'${FFLocalizations.of(context).getVariableText(ptText: "Modelo", enText: "Model")}:':
|
||||||
|
item['model'].toString().toUpperCase(),
|
||||||
|
if (item['licensePlate'] != null && item['licensePlate'] != '')
|
||||||
|
'${FFLocalizations.of(context).getVariableText(ptText: "Placa", enText: "License Plate")}:':
|
||||||
|
item['licensePlate'].toString().toUpperCase(),
|
||||||
|
if (item['color'] != null && item['color'] != '')
|
||||||
|
'${FFLocalizations.of(context).getVariableText(ptText: "Cor", enText: "Color")}:':
|
||||||
|
item['color'].toString().toUpperCase(),
|
||||||
|
if (item['personName'] != null && item['personName'] != '')
|
||||||
|
'${FFLocalizations.of(context).getVariableText(ptText: "Proprietário", enText: "Owner")}:':
|
||||||
|
item['personName'].toString().toUpperCase(),
|
||||||
|
if (item['tag'] != null && item['tag'] != '')
|
||||||
|
'${FFLocalizations.of(context).getVariableText(ptText: "Tag", enText: "Tag")}:':
|
||||||
|
item['tag'].toString().toUpperCase(),
|
||||||
|
}),
|
||||||
|
statusHashMap: [],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,141 +0,0 @@
|
||||||
part of 'vehicles_on_the_property.dart';
|
|
||||||
|
|
||||||
/// [VehicleRegisterScreen] is a StatefulWidget that displays a form to register a vehicle.
|
|
||||||
|
|
||||||
// ignore: must_be_immutable
|
|
||||||
class VehicleRegisterScreen extends StatefulWidget {
|
|
||||||
VehicleRegisterScreen(this.model, {super.key});
|
|
||||||
late VehicleModel model;
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<VehicleRegisterScreen> createState() => _VehicleRegisterScreenState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _VehicleRegisterScreenState extends State<VehicleRegisterScreen> {
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return SingleChildScrollView(
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.max,
|
|
||||||
children: [
|
|
||||||
_buildHeader(context),
|
|
||||||
_buildBody(context),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Form _buildBody(BuildContext context) {
|
|
||||||
return Form(
|
|
||||||
key: widget.model.registerFormKey,
|
|
||||||
autovalidateMode: AutovalidateMode.onUserInteraction,
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.max,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
|
||||||
children: [
|
|
||||||
_buildCustomInput(
|
|
||||||
context: context,
|
|
||||||
controller: widget.model.textFieldControllerLicensePlate!,
|
|
||||||
validator: widget.model.textControllerLicensePlateValidator,
|
|
||||||
focusNode: widget.model.textFieldFocusLicensePlate!,
|
|
||||||
labelText: FFLocalizations.of(context)
|
|
||||||
.getVariableText(ptText: 'Placa', enText: 'License Plate'),
|
|
||||||
hintText: FFLocalizations.of(context)
|
|
||||||
.getVariableText(ptText: 'Placa', enText: 'License Plate'),
|
|
||||||
suffixIcon: Symbols.format_color_text,
|
|
||||||
inputFormatters: [UpperCaseTextFormatter()],
|
|
||||||
maxLength: 7,
|
|
||||||
),
|
|
||||||
_buildCustomInput(
|
|
||||||
context: context,
|
|
||||||
controller: widget.model.textFieldControllerModel!,
|
|
||||||
validator: widget.model.textControllerModelValidator,
|
|
||||||
focusNode: widget.model.textFieldFocusModel!,
|
|
||||||
labelText: FFLocalizations.of(context)
|
|
||||||
.getVariableText(ptText: 'Modelo', enText: 'Model'),
|
|
||||||
hintText: FFLocalizations.of(context).getVariableText(
|
|
||||||
ptText: 'Ex: Voyage, Ford', enText: 'e.g. Voyage, Ford'),
|
|
||||||
suffixIcon: Symbols.car_repair,
|
|
||||||
inputFormatters: [],
|
|
||||||
),
|
|
||||||
_buildCustomInput(
|
|
||||||
context: context,
|
|
||||||
controller: widget.model.textFieldControllerColor!,
|
|
||||||
validator: widget.model.textControllerColorValidator,
|
|
||||||
focusNode: widget.model.textFieldFocusColor!,
|
|
||||||
labelText: FFLocalizations.of(context)
|
|
||||||
.getVariableText(ptText: 'Cor', enText: 'Color'),
|
|
||||||
hintText: FFLocalizations.of(context).getVariableText(
|
|
||||||
ptText: 'Ex: Preto, Amarelo, Branco',
|
|
||||||
enText: 'e.g. Black, Yellow, White'),
|
|
||||||
suffixIcon: Symbols.palette,
|
|
||||||
inputFormatters: [],
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.fromLTRB(70, 20, 70, 30),
|
|
||||||
child: SubmitButtonUtil(
|
|
||||||
labelText: FFLocalizations.of(context)
|
|
||||||
.getVariableText(ptText: 'Cadastrar', enText: 'Register'),
|
|
||||||
onPressed: widget.model
|
|
||||||
.isFormValid(context, widget.model.registerFormKey)
|
|
||||||
? widget.model.registerVehicle
|
|
||||||
: null,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildCustomInput({
|
|
||||||
required BuildContext context,
|
|
||||||
required TextEditingController controller,
|
|
||||||
required String? Function(BuildContext, String?) validator,
|
|
||||||
required FocusNode focusNode,
|
|
||||||
required String labelText,
|
|
||||||
required String hintText,
|
|
||||||
required IconData suffixIcon,
|
|
||||||
required final List<TextInputFormatter>? inputFormatters,
|
|
||||||
int maxLength = 80,
|
|
||||||
}) {
|
|
||||||
return CustomInputUtil(
|
|
||||||
controller: controller,
|
|
||||||
validator: (value) => validator(context, value),
|
|
||||||
focusNode: focusNode,
|
|
||||||
labelText: labelText,
|
|
||||||
hintText: hintText,
|
|
||||||
suffixIcon: suffixIcon,
|
|
||||||
haveMaxLength: true,
|
|
||||||
onChanged: (value) => setState(() {}),
|
|
||||||
inputFormatters: inputFormatters,
|
|
||||||
maxLength: maxLength,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Align _buildHeader(BuildContext context) {
|
|
||||||
double limitedHeaderFontSize =
|
|
||||||
LimitedFontSizeUtil.getHeaderFontSize(context);
|
|
||||||
|
|
||||||
return Align(
|
|
||||||
alignment: const AlignmentDirectional(-1.0, 0.0),
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsetsDirectional.fromSTEB(24.0, 20, 0.0, 15),
|
|
||||||
child: Text(
|
|
||||||
FFLocalizations.of(context).getVariableText(
|
|
||||||
ptText:
|
|
||||||
'Preencha o formulário de cadastro com os dados do seu veículo',
|
|
||||||
enText: 'Fill out the registration form with your vehicle data',
|
|
||||||
),
|
|
||||||
textAlign: TextAlign.start,
|
|
||||||
style: FlutterFlowTheme.of(context).bodyMedium.override(
|
|
||||||
fontFamily: FlutterFlowTheme.of(context).bodyMediumFamily,
|
|
||||||
letterSpacing: 0.0,
|
|
||||||
useGoogleFonts: GoogleFonts.asMap()
|
|
||||||
.containsKey(FlutterFlowTheme.of(context).bodyMediumFamily),
|
|
||||||
fontSize: limitedHeaderFontSize,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,140 +0,0 @@
|
||||||
part of 'vehicles_on_the_property.dart';
|
|
||||||
|
|
||||||
/// [VehicleUpdateScreen] is a StatefulWidget that displays a form to update a vehicle.
|
|
||||||
|
|
||||||
// ignore: must_be_immutable
|
|
||||||
class VehicleUpdateScreen extends StatefulWidget {
|
|
||||||
VehicleUpdateScreen(this.model, {super.key});
|
|
||||||
late VehicleModel model;
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<VehicleUpdateScreen> createState() => _VehicleUpdateScreenState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _VehicleUpdateScreenState extends State<VehicleUpdateScreen> {
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return SingleChildScrollView(
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.max,
|
|
||||||
children: [
|
|
||||||
_buildHeader(context),
|
|
||||||
buildBody(context),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Form buildBody(BuildContext context) {
|
|
||||||
return Form(
|
|
||||||
key: widget.model.updateFormKey,
|
|
||||||
autovalidateMode: AutovalidateMode.onUserInteraction,
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.max,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
|
||||||
children: [
|
|
||||||
_buildCustomInput(
|
|
||||||
context: context,
|
|
||||||
controller: widget.model.textFieldControllerLicensePlate!,
|
|
||||||
validator: widget.model.textControllerLicensePlateValidator,
|
|
||||||
focusNode: widget.model.textFieldFocusLicensePlate!,
|
|
||||||
labelText: FFLocalizations.of(context)
|
|
||||||
.getVariableText(ptText: 'Placa', enText: 'License Plate'),
|
|
||||||
hintText: FFLocalizations.of(context)
|
|
||||||
.getVariableText(ptText: 'Placa', enText: 'License Plate'),
|
|
||||||
suffixIcon: Symbols.format_color_text,
|
|
||||||
inputFormatters: [UpperCaseTextFormatter()],
|
|
||||||
maxLength: 7,
|
|
||||||
),
|
|
||||||
_buildCustomInput(
|
|
||||||
context: context,
|
|
||||||
controller: widget.model.textFieldControllerModel!,
|
|
||||||
validator: widget.model.textControllerModelValidator,
|
|
||||||
focusNode: widget.model.textFieldFocusModel!,
|
|
||||||
labelText: FFLocalizations.of(context)
|
|
||||||
.getVariableText(ptText: 'Modelo', enText: 'Model'),
|
|
||||||
hintText: FFLocalizations.of(context).getVariableText(
|
|
||||||
ptText: 'Ex: Voyage, Ford', enText: 'e.g. Voyage, Ford'),
|
|
||||||
suffixIcon: Symbols.car_repair,
|
|
||||||
inputFormatters: [],
|
|
||||||
),
|
|
||||||
_buildCustomInput(
|
|
||||||
context: context,
|
|
||||||
controller: widget.model.textFieldControllerColor!,
|
|
||||||
validator: widget.model.textControllerColorValidator,
|
|
||||||
focusNode: widget.model.textFieldFocusColor!,
|
|
||||||
labelText: FFLocalizations.of(context)
|
|
||||||
.getVariableText(ptText: 'Cor', enText: 'Color'),
|
|
||||||
hintText: FFLocalizations.of(context).getVariableText(
|
|
||||||
ptText: 'Ex: Preto, Amarelo, Branco',
|
|
||||||
enText: 'e.g. Black, Yellow, White'),
|
|
||||||
suffixIcon: Symbols.palette,
|
|
||||||
inputFormatters: [],
|
|
||||||
),
|
|
||||||
_buildSubmitButton(context),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildHeader(BuildContext context) {
|
|
||||||
return Align(
|
|
||||||
alignment: const AlignmentDirectional(-1.0, 0.0),
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsetsDirectional.fromSTEB(24.0, 20, 0.0, 15),
|
|
||||||
child: Text(
|
|
||||||
FFLocalizations.of(context).getVariableText(
|
|
||||||
ptText:
|
|
||||||
'Preencha o formulário de alteração com os dados do seu veículo',
|
|
||||||
enText: 'Fill out the update form with your vehicle data',
|
|
||||||
),
|
|
||||||
textAlign: TextAlign.start,
|
|
||||||
style: FlutterFlowTheme.of(context).bodyMedium.override(
|
|
||||||
fontFamily: FlutterFlowTheme.of(context).bodyMediumFamily,
|
|
||||||
letterSpacing: 0.0,
|
|
||||||
useGoogleFonts: GoogleFonts.asMap()
|
|
||||||
.containsKey(FlutterFlowTheme.of(context).bodyMediumFamily),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildCustomInput({
|
|
||||||
required BuildContext context,
|
|
||||||
required TextEditingController controller,
|
|
||||||
required String? Function(BuildContext, String?) validator,
|
|
||||||
required FocusNode focusNode,
|
|
||||||
required String labelText,
|
|
||||||
required String hintText,
|
|
||||||
required IconData suffixIcon,
|
|
||||||
required List<TextInputFormatter>? inputFormatters,
|
|
||||||
int maxLength = 80,
|
|
||||||
}) {
|
|
||||||
return CustomInputUtil(
|
|
||||||
controller: controller,
|
|
||||||
validator: (value) => validator(context, value),
|
|
||||||
focusNode: focusNode,
|
|
||||||
labelText: labelText,
|
|
||||||
hintText: hintText,
|
|
||||||
suffixIcon: suffixIcon,
|
|
||||||
haveMaxLength: true,
|
|
||||||
onChanged: (value) => setState(() {}),
|
|
||||||
inputFormatters: inputFormatters,
|
|
||||||
maxLength: maxLength,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildSubmitButton(BuildContext context) {
|
|
||||||
return Padding(
|
|
||||||
padding: const EdgeInsets.fromLTRB(70, 20, 70, 30),
|
|
||||||
child: SubmitButtonUtil(
|
|
||||||
labelText: FFLocalizations.of(context)
|
|
||||||
.getVariableText(ptText: 'Salvar', enText: 'Save'),
|
|
||||||
onPressed: widget.model.isFormValid(context, widget.model.updateFormKey)
|
|
||||||
? () => widget.model.updateVehicle()
|
|
||||||
: null,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,184 +1,149 @@
|
||||||
import 'dart:collection';
|
|
||||||
import 'dart:developer';
|
|
||||||
|
|
||||||
import 'package:auto_size_text/auto_size_text.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
import 'package:google_fonts/google_fonts.dart';
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
import 'package:hub/components/atomic_components/shared_components_atoms/custom_input.dart';
|
|
||||||
import 'package:hub/components/atomic_components/shared_components_atoms/submit_button.dart';
|
|
||||||
import 'package:hub/components/atomic_components/shared_components_atoms/tabview.dart';
|
|
||||||
import 'package:hub/components/templates_components/card_item_template_component/card_item_template_component_widget.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/backend/index.dart';
|
||||||
import 'package:hub/features/module/index.dart';
|
import 'package:hub/flutter_flow/flutter_flow_icon_button.dart';
|
||||||
import 'package:hub/flutter_flow/index.dart';
|
import 'package:hub/flutter_flow/flutter_flow_theme.dart';
|
||||||
|
import 'package:hub/flutter_flow/flutter_flow_util.dart';
|
||||||
import 'package:hub/pages/vehicles_on_the_property/vehicle_model.dart';
|
import 'package:hub/pages/vehicles_on_the_property/vehicle_model.dart';
|
||||||
import 'package:hub/shared/extensions.dart';
|
|
||||||
import 'package:hub/shared/mixins/pageable_mixin.dart';
|
|
||||||
import 'package:hub/shared/utils/dialog_util.dart';
|
import 'package:hub/shared/utils/dialog_util.dart';
|
||||||
import 'package:hub/shared/utils/license_util.dart';
|
|
||||||
import 'package:hub/shared/utils/limited_text_size.dart';
|
import 'package:hub/shared/utils/limited_text_size.dart';
|
||||||
import 'package:hub/shared/utils/log_util.dart';
|
import 'package:hub/shared/utils/log_util.dart';
|
||||||
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
|
|
||||||
import 'package:material_symbols_icons/symbols.dart';
|
|
||||||
|
|
||||||
part 'vehicle_history_screen.dart';
|
class VehicleOnTheProperty extends StatefulWidget {
|
||||||
part 'vehicle_register_screen.dart';
|
const VehicleOnTheProperty({super.key});
|
||||||
part 'vehicle_update_screen.dart';
|
|
||||||
|
|
||||||
/// [VehiclePage] is a StatefulWidget that displays the vehicle screens.
|
|
||||||
class VehiclePage extends StatefulWidget {
|
|
||||||
const VehiclePage({super.key});
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
// ignore: library_private_types_in_public_api
|
_VehicleOnThePropertyState createState() => _VehicleOnThePropertyState();
|
||||||
_VehiclePageState createState() => _VehiclePageState();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class _VehiclePageState extends State<VehiclePage>
|
class _VehicleOnThePropertyState extends State<VehicleOnTheProperty>
|
||||||
with TickerProviderStateMixin {
|
with TickerProviderStateMixin {
|
||||||
|
late ScrollController _scrollController;
|
||||||
|
|
||||||
|
int _pageNumber = 1;
|
||||||
|
bool _hasData = false;
|
||||||
|
bool _loading = false;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
late final VehicleModel _model;
|
late final VehicleModel model;
|
||||||
|
|
||||||
|
late Future<void> _future;
|
||||||
|
List<dynamic> _wrap = [];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_model = createModel(context, () => VehicleModel());
|
model = createModel(context, () => VehicleModel());
|
||||||
|
_future = _fetchVisits();
|
||||||
_model.updateOnChange = true;
|
_scrollController = ScrollController()
|
||||||
_model.onUpdateVehicle = () {
|
..addListener(() {
|
||||||
safeSetState(() {
|
if (_scrollController.position.atEdge &&
|
||||||
_model.clearFields();
|
_scrollController.position.pixels != 0) {
|
||||||
|
_loadMore();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
|
||||||
_model.onRegisterVehicle = () {
|
|
||||||
safeSetState(() {
|
|
||||||
_model.clearFields();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
_model.safeSetState = () {
|
|
||||||
safeSetState(() {});
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// @override
|
@override
|
||||||
// void dispose() {
|
void dispose() {
|
||||||
// super.dispose();
|
_scrollController.dispose();
|
||||||
// }
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final backgroundColor = FlutterFlowTheme.of(context).primaryBackground;
|
late final limitedHeaderTextSize =
|
||||||
|
LimitedFontSizeUtil.getHeaderFontSize(context);
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: backgroundColor,
|
backgroundColor: FlutterFlowTheme.of(context).primaryBackground,
|
||||||
appBar: _buildHeader(context),
|
appBar: _appBar(context),
|
||||||
body: _buildBody(context),
|
body: Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
if (_hasData == false && _pageNumber <= 1 && _loading == false)
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
Center(
|
||||||
|
child: Text(
|
||||||
|
FFLocalizations.of(context).getVariableText(
|
||||||
|
ptText: "Nenhum veículo encontrado!",
|
||||||
|
enText: "No vehicle found",
|
||||||
|
),
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: 'Nunito',
|
||||||
|
fontSize: limitedHeaderTextSize,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
else if (_hasData == true || _pageNumber >= 1)
|
||||||
|
Expanded(
|
||||||
|
child: FutureBuilder<void>(
|
||||||
|
future: _future,
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
return ListView.builder(
|
||||||
|
shrinkWrap: true,
|
||||||
|
physics: const BouncingScrollPhysics(),
|
||||||
|
controller: _scrollController,
|
||||||
|
itemCount: _wrap.length + 1,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
if (index == 0) {
|
||||||
|
// Add your item here
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.only(right: 30, top: 10),
|
||||||
|
child: Text(
|
||||||
|
'',
|
||||||
|
textAlign: TextAlign.right,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
final item = _wrap[index - 1];
|
||||||
|
return _item(context, item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
)),
|
||||||
|
if (_hasData == true && _loading == true)
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.only(top: 15, bottom: 15),
|
||||||
|
child: Center(
|
||||||
|
child: CircularProgressIndicator(
|
||||||
|
valueColor: AlwaysStoppedAnimation<Color>(
|
||||||
|
FlutterFlowTheme.of(context).primary,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
].addToStart(const SizedBox(height: 0)),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// [Body] of the page.
|
PreferredSizeWidget _appBar(BuildContext context) {
|
||||||
FutureBuilder<bool> _buildBody(BuildContext context) {
|
|
||||||
Widget progressIndicator() {
|
|
||||||
return CircularProgressIndicator(
|
|
||||||
valueColor: AlwaysStoppedAnimation<Color>(
|
|
||||||
FlutterFlowTheme.of(context).primary,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return FutureBuilder<bool>(
|
|
||||||
future: _initializeModule(),
|
|
||||||
builder: (context, snapshot) {
|
|
||||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
|
||||||
return progressIndicator();
|
|
||||||
} else if (snapshot.hasError) {
|
|
||||||
return progressIndicator();
|
|
||||||
} else if (snapshot.hasData && snapshot.data == true) {
|
|
||||||
return _buildVehicleManager(context);
|
|
||||||
} else {
|
|
||||||
return _buildVehicleHistory(context);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<bool> _initializeModule() async {
|
|
||||||
try {
|
|
||||||
final module =
|
|
||||||
await LicenseRepositoryImpl().getModule('FRE-HUB-VEHICLES-MANAGER');
|
|
||||||
return await LicenseUtil.processModule(module);
|
|
||||||
} catch (e) {
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
|
||||||
context.pop();
|
|
||||||
await DialogUtil.errorDefault(navigatorKey.currentContext!);
|
|
||||||
});
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void onEditingChanged([bool? value]) {
|
|
||||||
bool isFirst = _model.tabBarController.index == 0;
|
|
||||||
|
|
||||||
if (_model.isEditing & isFirst) {
|
|
||||||
_model.handleEditingChanged(false);
|
|
||||||
}
|
|
||||||
if (isFirst) {
|
|
||||||
setState(() {});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildVehicleHistory(BuildContext context) {
|
|
||||||
return VehicleHistoryScreen(_model);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildVehicleManager(BuildContext context) {
|
|
||||||
final vehicleHistoryScreenLabel = FFLocalizations.of(context)
|
|
||||||
.getVariableText(ptText: 'Consultar', enText: 'History');
|
|
||||||
final vehicleRegisterScreenLabel = FFLocalizations.of(context)
|
|
||||||
.getVariableText(ptText: 'Cadastrar', enText: 'Register');
|
|
||||||
final vehicleUpdateScreenLabel = FFLocalizations.of(context)
|
|
||||||
.getVariableText(ptText: 'Editar', enText: 'Edit');
|
|
||||||
|
|
||||||
return TabViewUtil(
|
|
||||||
context: context,
|
|
||||||
model: _model,
|
|
||||||
labelTab1: vehicleHistoryScreenLabel,
|
|
||||||
labelTab2: _model.isEditing
|
|
||||||
? vehicleUpdateScreenLabel
|
|
||||||
: vehicleRegisterScreenLabel,
|
|
||||||
controller: _model.tabBarController,
|
|
||||||
widget1: VehicleHistoryScreen(_model),
|
|
||||||
widget2: _model.isEditing
|
|
||||||
? VehicleUpdateScreen(_model)
|
|
||||||
: VehicleRegisterScreen(_model),
|
|
||||||
onEditingChanged: onEditingChanged,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// -----------------------------------
|
|
||||||
/// [Header] of the page.
|
|
||||||
PreferredSizeWidget _buildHeader(BuildContext context) {
|
|
||||||
final theme = FlutterFlowTheme.of(context);
|
|
||||||
final backgroundColor = theme.primaryBackground;
|
|
||||||
final primaryText = theme.primaryText;
|
|
||||||
final title = FFLocalizations.of(context)
|
|
||||||
.getVariableText(enText: 'Vehicles', ptText: 'Veículos');
|
|
||||||
final titleStyle = theme.headlineMedium.override(
|
|
||||||
fontFamily: theme.headlineMediumFamily,
|
|
||||||
color: primaryText,
|
|
||||||
fontSize: 16.0,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
letterSpacing: 0.0,
|
|
||||||
useGoogleFonts:
|
|
||||||
GoogleFonts.asMap().containsKey(theme.headlineMediumFamily),
|
|
||||||
);
|
|
||||||
final backButton = _backButton(context, theme);
|
|
||||||
|
|
||||||
return AppBar(
|
return AppBar(
|
||||||
backgroundColor: backgroundColor,
|
backgroundColor: FlutterFlowTheme.of(context).primaryBackground,
|
||||||
automaticallyImplyLeading: false,
|
automaticallyImplyLeading: false,
|
||||||
title: Text(title, style: titleStyle),
|
title: Text(
|
||||||
leading: backButton,
|
FFLocalizations.of(context)
|
||||||
|
.getVariableText(enText: 'Vehicles', ptText: 'Veículos'),
|
||||||
|
style: FlutterFlowTheme.of(context).headlineMedium.override(
|
||||||
|
fontFamily: FlutterFlowTheme.of(context).headlineMediumFamily,
|
||||||
|
color: FlutterFlowTheme.of(context).primaryText,
|
||||||
|
fontSize: 16.0,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
useGoogleFonts: GoogleFonts.asMap().containsKey(
|
||||||
|
FlutterFlowTheme.of(context).headlineMediumFamily),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
leading: _backButton(context, FlutterFlowTheme.of(context)),
|
||||||
centerTitle: true,
|
centerTitle: true,
|
||||||
elevation: 0.0,
|
elevation: 0.0,
|
||||||
actions: [],
|
actions: [],
|
||||||
|
@ -186,22 +151,131 @@ class _VehiclePageState extends State<VehiclePage>
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _backButton(BuildContext context, FlutterFlowTheme theme) {
|
Widget _backButton(BuildContext context, FlutterFlowTheme theme) {
|
||||||
final Icon icon = Icon(
|
|
||||||
Icons.keyboard_arrow_left,
|
|
||||||
color: theme.primaryText,
|
|
||||||
size: 30.0,
|
|
||||||
);
|
|
||||||
onPressed() => Navigator.of(context).pop();
|
|
||||||
return FlutterFlowIconButton(
|
return FlutterFlowIconButton(
|
||||||
key: ValueKey<String>('BackNavigationAppBar'),
|
key: ValueKey<String>('BackNavigationAppBar'),
|
||||||
borderColor: Colors.transparent,
|
borderColor: Colors.transparent,
|
||||||
borderRadius: 30.0,
|
borderRadius: 30.0,
|
||||||
borderWidth: 1.0,
|
borderWidth: 1.0,
|
||||||
buttonSize: 60.0,
|
buttonSize: 60.0,
|
||||||
icon: icon,
|
icon: Icon(
|
||||||
onPressed: onPressed,
|
Icons.keyboard_arrow_left,
|
||||||
|
color: theme.primaryText,
|
||||||
|
size: 30.0,
|
||||||
|
),
|
||||||
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// -----------------------------------
|
Future<ApiCallResponse?> _fetchVisits() async {
|
||||||
|
try {
|
||||||
|
setState(() => _loading = true);
|
||||||
|
|
||||||
|
var response = await FreAccessWSGlobal.getVehiclesByProperty
|
||||||
|
.call(_pageNumber.toString());
|
||||||
|
|
||||||
|
final List<dynamic> vehicles = response.jsonBody['vehicles'] ?? [];
|
||||||
|
safeSetState(() => count = response.jsonBody['total_rows'] ?? 0);
|
||||||
|
|
||||||
|
if (vehicles.isNotEmpty) {
|
||||||
|
setState(() {
|
||||||
|
_wrap.addAll(vehicles);
|
||||||
|
_hasData = true;
|
||||||
|
_loading = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
_showNoMoreDataSnackBar(context);
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
_hasData = false;
|
||||||
|
_loading = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
return null;
|
||||||
|
} catch (e, s) {
|
||||||
|
DialogUtil.errorDefault(context);
|
||||||
|
LogUtil.requestAPIFailed(
|
||||||
|
"proccessRequest.php", "", "Consulta de Veículo", e, s);
|
||||||
|
setState(() {
|
||||||
|
_hasData = false;
|
||||||
|
_loading = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _loadMore() {
|
||||||
|
if (_hasData == true) {
|
||||||
|
_pageNumber++;
|
||||||
|
|
||||||
|
_future = _fetchVisits();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _showNoMoreDataSnackBar(BuildContext context) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text(
|
||||||
|
FFLocalizations.of(context).getVariableText(
|
||||||
|
ptText: "Não há mais dados.",
|
||||||
|
enText: "No more data.",
|
||||||
|
),
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: LimitedFontSizeUtil.getBodyFontSize(context),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
duration: const Duration(seconds: 3),
|
||||||
|
backgroundColor: FlutterFlowTheme.of(context).primary,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _item(BuildContext context, dynamic uItem) {
|
||||||
|
return CardItemTemplateComponentWidget(
|
||||||
|
imagePath: null,
|
||||||
|
labelsHashMap: {
|
||||||
|
'${FFLocalizations.of(context).getVariableText(ptText: "Placa", enText: "License Plate")}:':
|
||||||
|
uItem['licensePlate'] ?? '',
|
||||||
|
'${FFLocalizations.of(context).getVariableText(ptText: "Modelo", enText: "Model")}:':
|
||||||
|
uItem['model'] ?? '',
|
||||||
|
'${FFLocalizations.of(context).getVariableText(ptText: "Tag", enText: "Tag")}:':
|
||||||
|
uItem['tag'] ?? '',
|
||||||
|
},
|
||||||
|
statusHashMap: [],
|
||||||
|
onTapCardItemAction: () async {
|
||||||
|
await showDialog(
|
||||||
|
useSafeArea: true,
|
||||||
|
context: context,
|
||||||
|
builder: (context) {
|
||||||
|
return Dialog(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: model.buildVehicleDetails(
|
||||||
|
item: uItem,
|
||||||
|
context: context,
|
||||||
|
model: model,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
).whenComplete(() {
|
||||||
|
safeSetState(() {
|
||||||
|
_pageNumber = 1;
|
||||||
|
_wrap = [];
|
||||||
|
_future = _fetchVisits()
|
||||||
|
.then((value) => value!.jsonBody['vehicles'] ?? []);
|
||||||
|
});
|
||||||
|
}).catchError((e, s) {
|
||||||
|
DialogUtil.errorDefault(context);
|
||||||
|
LogUtil.requestAPIFailed(
|
||||||
|
"proccessRequest.php", "", "Consulta de Veículos", e, s);
|
||||||
|
safeSetState(() {
|
||||||
|
_hasData = false;
|
||||||
|
_loading = false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ import 'package:hub/flutter_flow/flutter_flow_theme.dart';
|
||||||
import 'package:hub/flutter_flow/internationalization.dart';
|
import 'package:hub/flutter_flow/internationalization.dart';
|
||||||
import 'package:hub/pages/vehicles_on_the_property/vehicles_on_the_property.dart';
|
import 'package:hub/pages/vehicles_on_the_property/vehicles_on_the_property.dart';
|
||||||
|
|
||||||
class VisitsModel extends FlutterFlowModel<VehiclePage> {
|
class VisitsModel extends FlutterFlowModel<VehicleOnTheProperty> {
|
||||||
static VisitsModel? _instance;
|
static VisitsModel? _instance;
|
||||||
|
|
||||||
VisitsModel._internal({this.onRefresh});
|
VisitsModel._internal({this.onRefresh});
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
export 'enums/enum_throw_exception.dart';
|
|
|
@ -0,0 +1 @@
|
||||||
|
export 'enum_throw_exception.dart';
|
|
@ -1,3 +0,0 @@
|
||||||
export 'extensions/dialog_extensions.dart';
|
|
||||||
export 'extensions/flutter_secure_storage_extensions.dart';
|
|
||||||
export 'extensions/string_extensions.dart';
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
export 'dialog_extensions.dart';
|
||||||
|
export 'flutter_secure_storage_extensions.dart';
|
||||||
|
export 'string_extensions.dart';
|
|
@ -1,7 +1,7 @@
|
||||||
import 'dart:ui';
|
import 'dart:ui';
|
||||||
|
|
||||||
extension StringNullableExtensions on String? {
|
extension StringNullableExtensions on String? {
|
||||||
bool get toBoolean {
|
bool toBoolean() {
|
||||||
if (this == null) return false;
|
if (this == null) return false;
|
||||||
return this!.toLowerCase() == 'true';
|
return this!.toLowerCase() == 'true';
|
||||||
}
|
}
|
||||||
|
@ -11,16 +11,10 @@ extension StringNullableExtensions on String? {
|
||||||
if (this == '') return true;
|
if (this == '') return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool get isNotNullAndEmpty {
|
|
||||||
if (this == null) return false;
|
|
||||||
if (this == '') return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension StringExtensions on String {
|
extension StringExtensions on String {
|
||||||
bool get toBoolean {
|
bool toBoolean() {
|
||||||
return toLowerCase() == 'true';
|
return toLowerCase() == 'true';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
export 'mixins/pegeable_mixin.dart';
|
|
||||||
export 'mixins/status_mixin.dart';
|
|
||||||
export 'mixins/switcher_mixin.dart';
|
|
||||||
export 'mixins/template_mixin.dart';
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
export 'pegeable_mixin.dart';
|
||||||
|
export 'status_mixin.dart';
|
||||||
|
export 'switcher_mixin.dart';
|
|
@ -1,98 +0,0 @@
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:hub/flutter_flow/index.dart';
|
|
||||||
import 'package:hub/shared/utils/limited_text_size.dart';
|
|
||||||
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
|
|
||||||
|
|
||||||
extension PagedListViewExtension<PageKeyType, ItemType>
|
|
||||||
on PagedSliverList<PageKeyType, ItemType> {}
|
|
||||||
|
|
||||||
mixin Pageable<T extends StatefulWidget> on State<T> {
|
|
||||||
Expanded buildPaginatedListView<X, Y>(
|
|
||||||
String noDataFound,
|
|
||||||
PagingController<X, Y> pg,
|
|
||||||
Widget Function(BuildContext, Y, int) itemBuilder) {
|
|
||||||
final theme = FlutterFlowTheme.of(context);
|
|
||||||
|
|
||||||
return Expanded(
|
|
||||||
child: RefreshIndicator(
|
|
||||||
backgroundColor: theme.primaryBackground,
|
|
||||||
color: theme.primary,
|
|
||||||
onRefresh: () async => pg.refresh(),
|
|
||||||
child: PagedListView<X, Y>(
|
|
||||||
pagingController: pg,
|
|
||||||
builderDelegate: PagedChildBuilderDelegate<Y>(
|
|
||||||
animateTransitions: true,
|
|
||||||
|
|
||||||
itemBuilder: (context, item, index) =>
|
|
||||||
itemBuilder(context, item, index),
|
|
||||||
// noMoreItemsIndicatorBuilder: ,
|
|
||||||
newPageProgressIndicatorBuilder: (context) =>
|
|
||||||
buildLoadingIndicator(context),
|
|
||||||
firstPageProgressIndicatorBuilder: (context) =>
|
|
||||||
buildLoadingIndicator(context),
|
|
||||||
noItemsFoundIndicatorBuilder: (context) =>
|
|
||||||
buildNoDataFound(context, noDataFound),
|
|
||||||
// firstPageErrorIndicatorBuilder: (context) => const Placeholder(),
|
|
||||||
// newPageErrorIndicatorBuilder: (context) => const Placeholder(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> fetchPage({
|
|
||||||
required Future<(bool, dynamic)> Function() dataProvider,
|
|
||||||
required void Function(dynamic data) onDataAvailable,
|
|
||||||
required void Function(dynamic data) onDataUnavailable,
|
|
||||||
required void Function(Object error, StackTrace stackTrace) onFetchError,
|
|
||||||
}) async {
|
|
||||||
try {
|
|
||||||
final (bool isDataAvailable, dynamic data) = await dataProvider();
|
|
||||||
if (isDataAvailable) {
|
|
||||||
onDataAvailable(data);
|
|
||||||
} else {
|
|
||||||
onDataUnavailable(data);
|
|
||||||
}
|
|
||||||
} catch (error, stackTrace) {
|
|
||||||
onFetchError(error, stackTrace);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void showNoMoreDataSnackBar(BuildContext context) {
|
|
||||||
final message = FFLocalizations.of(context).getVariableText(
|
|
||||||
ptText: "Não há mais dados.",
|
|
||||||
enText: "No more data.",
|
|
||||||
);
|
|
||||||
|
|
||||||
showSnackbarMessenger(context, message, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget buildNoDataFound(BuildContext context, String title) {
|
|
||||||
final headerFontSize = LimitedFontSizeUtil.getHeaderFontSize(context);
|
|
||||||
// final bodyFontSize = LimitedFontSizeUtil.getBodyFontSize(context);
|
|
||||||
return Expanded(
|
|
||||||
child: Center(
|
|
||||||
child: Text(
|
|
||||||
title,
|
|
||||||
style: TextStyle(
|
|
||||||
fontFamily: 'Nunito',
|
|
||||||
fontSize: headerFontSize,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget buildLoadingIndicator(BuildContext context) {
|
|
||||||
return Container(
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 15),
|
|
||||||
child: Center(
|
|
||||||
child: CircularProgressIndicator(
|
|
||||||
valueColor: AlwaysStoppedAnimation<Color>(
|
|
||||||
FlutterFlowTheme.of(context).primary,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -44,7 +44,7 @@ mixin Template {
|
||||||
),
|
),
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
Symbols.info_i_rounded,
|
Symbols.info_i_rounded,
|
||||||
color: FlutterFlowTheme.of(context).primaryText,
|
color: Colors.black,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
];
|
];
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
export 'utils/biometric_util.dart';
|
|
||||||
export 'utils/device_util.dart';
|
|
||||||
export 'utils/dialog_util.dart';
|
|
||||||
export 'utils/image_util.dart';
|
|
||||||
export 'utils/limited_text_size.dart';
|
|
||||||
export 'utils/loading_util.dart';
|
|
||||||
export 'utils/log_util.dart';
|
|
||||||
export 'utils/path_util.dart';
|
|
||||||
export 'utils/share_util.dart';
|
|
||||||
export 'utils/snackbar_util.dart';
|
|
||||||
export 'utils/string_util.dart';
|
|
||||||
export 'utils/text_util.dart';
|
|
||||||
export 'utils/validator_util.dart';
|
|
||||||
export 'utils/webview_util.dart';
|
|
||||||
export 'utils/color_util.dart';
|
|
|
@ -1,48 +0,0 @@
|
||||||
import 'dart:ui';
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class ColorUtil {
|
|
||||||
static Color getContrastColor(Color a, Color b) {
|
|
||||||
double luminance(Color color) {
|
|
||||||
return (0.299 * color.r + 0.587 * color.g + 0.114 * color.b) / 255;
|
|
||||||
}
|
|
||||||
|
|
||||||
double contrastRatio(Color a, Color b) {
|
|
||||||
final lumA = luminance(a) + 0.05;
|
|
||||||
final lumB = luminance(b) + 0.05;
|
|
||||||
return lumA > lumB ? lumA / lumB : lumB / lumA;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (contrastRatio(a, b) < 4.5) {
|
|
||||||
// Find a color with higher contrast within the same hue
|
|
||||||
final hsv = HSVColor.fromColor(a);
|
|
||||||
double hue = hsv.hue;
|
|
||||||
double saturation = hsv.saturation;
|
|
||||||
double brightness = hsv.value;
|
|
||||||
|
|
||||||
// Increase brightness to ensure higher contrast
|
|
||||||
brightness = brightness > 0.5 ? brightness - 0.5 : brightness + 0.5;
|
|
||||||
|
|
||||||
return HSVColor.fromAHSV(1.0, hue, saturation, brightness).toColor();
|
|
||||||
}
|
|
||||||
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Color getSelfContrastColor(Color color) {
|
|
||||||
final hsv = HSVColor.fromColor(color);
|
|
||||||
double hue = hsv.hue;
|
|
||||||
double saturation = hsv.saturation;
|
|
||||||
double brightness = hsv.value;
|
|
||||||
|
|
||||||
// Increase brightness to ensure higher contrast
|
|
||||||
brightness = brightness > 0.5 ? brightness - 0.5 : brightness + 0.5;
|
|
||||||
|
|
||||||
return HSVColor.fromAHSV(1.0, hue, saturation, brightness).toColor();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension ColorUtilExtension on Color {
|
|
||||||
Color get highlight => ColorUtil.getSelfContrastColor(this);
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
import 'dart:developer';
|
|
||||||
|
|
||||||
class DateTimeUtil {
|
|
||||||
static Future<bool> processStartDate(String startDate) async {
|
|
||||||
try {
|
|
||||||
if (startDate.isEmpty) return true;
|
|
||||||
final start = DateTime.tryParse(startDate);
|
|
||||||
if (start == null) return false;
|
|
||||||
return DateTime.now().isAfter(start);
|
|
||||||
} catch (e) {
|
|
||||||
log('Error processing start date for module: $e');
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Future<bool> processExpirationDate(String expirationDate) async {
|
|
||||||
try {
|
|
||||||
if (expirationDate.isEmpty) return false;
|
|
||||||
final expiration = DateTime.tryParse(expirationDate);
|
|
||||||
return expiration != null && DateTime.now().isAfter(expiration);
|
|
||||||
} catch (e) {
|
|
||||||
log('Error processing expiration date for module: $e');
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
export 'biometric_util.dart';
|
||||||
|
export 'device_util.dart';
|
||||||
|
export 'dialog_util.dart';
|
||||||
|
export 'image_util.dart';
|
||||||
|
export 'limited_text_size.dart';
|
||||||
|
export 'loading_util.dart';
|
||||||
|
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';
|
|
@ -1,18 +0,0 @@
|
||||||
import 'package:hub/features/module/index.dart';
|
|
||||||
import 'package:hub/flutter_flow/index.dart';
|
|
||||||
import 'package:hub/shared/utils/datetime_util.dart';
|
|
||||||
|
|
||||||
class LicenseUtil {
|
|
||||||
static Future<bool> processModule(String? module) async {
|
|
||||||
if (module == null) return false;
|
|
||||||
final moduleMap = await stringToMap(module);
|
|
||||||
final startDate = moduleMap['startDate'] ?? '';
|
|
||||||
final expirationDate = moduleMap['expirationDate'] ?? '';
|
|
||||||
final isStarted = await DateTimeUtil.processStartDate(startDate);
|
|
||||||
final isExpired = await DateTimeUtil.processExpirationDate(expirationDate);
|
|
||||||
if (isStarted && !isExpired)
|
|
||||||
return EnumDisplay.fromString(moduleMap["display"]) == EnumDisplay.active;
|
|
||||||
if (isExpired) return false;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
/// [Base]
|
|
||||||
library;
|
|
||||||
|
|
||||||
export 'widgets/page.dart';
|
|
||||||
export 'widgets/component.dart';
|
|
||||||
export 'widgets/screen.dart';
|
|
||||||
export 'widgets/model.dart';
|
|
||||||
export 'widgets/entity.dart';
|
|
||||||
|
|
||||||
/// [View]'s
|
|
||||||
export 'widgets/list_view.dart';
|
|
||||||
export 'widgets/read_view.dart';
|
|
||||||
export 'widgets/enhanced_carousel_view.dart';
|
|
||||||
export 'widgets/enhanced_list_view.dart';
|
|
||||||
export 'widgets/enhanced_search_view.dart';
|
|
||||||
|
|
||||||
/// [Component]'s
|
|
||||||
export 'widgets/text.dart';
|
|
|
@ -1,5 +1,4 @@
|
||||||
import 'package:flutter/material.dart';
|
part of 'widgets.dart';
|
||||||
import 'package:hub/shared/widgets.dart';
|
|
||||||
|
|
||||||
/// [ComponentWidget]
|
/// [ComponentWidget]
|
||||||
|
|
||||||
|
|
|
@ -1,123 +1,68 @@
|
||||||
import 'dart:developer';
|
part of 'widgets.dart';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
class EnhancedCarouselView<T> extends StatelessWidget {
|
||||||
import 'package:hub/flutter_flow/index.dart';
|
|
||||||
import 'package:hub/shared/utils.dart';
|
|
||||||
|
|
||||||
typedef EnhancedCarouselViewKey<T> = GlobalKey<_EnhancedCarouselViewState<T>>;
|
|
||||||
|
|
||||||
class EnhancedCarouselView<T> extends StatefulWidget {
|
|
||||||
final Future<List<T?>> Function() dataProvider;
|
final Future<List<T?>> Function() dataProvider;
|
||||||
final void Function(T?, BuildContext) filter;
|
final void Function(T, BuildContext) filter;
|
||||||
final Widget Function<T>(T? item, bool isSelected) itemBuilder;
|
final Widget Function<T>(T? item) itemBuilder;
|
||||||
final bool showIndicator;
|
|
||||||
|
|
||||||
const EnhancedCarouselView({
|
const EnhancedCarouselView({
|
||||||
super.key,
|
super.key,
|
||||||
required this.dataProvider,
|
required this.dataProvider,
|
||||||
required this.filter,
|
required this.filter,
|
||||||
required this.itemBuilder,
|
required this.itemBuilder,
|
||||||
this.showIndicator = false,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
|
||||||
_EnhancedCarouselViewState<T> createState() =>
|
|
||||||
_EnhancedCarouselViewState<T>();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _EnhancedCarouselViewState<T> extends State<EnhancedCarouselView<T>> {
|
|
||||||
T? selectedCategory;
|
|
||||||
|
|
||||||
bool itemIsSelected(T item) {
|
|
||||||
return selectedCategory == item;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final theme = FlutterFlowTheme.of(context);
|
final theme = FlutterFlowTheme.of(context);
|
||||||
final backgroundColor = theme.primary;
|
final backgroundColor = theme.primary;
|
||||||
final overlayColor = WidgetStateProperty.all(Colors.transparent);
|
final overlayColor = WidgetStateProperty.all(Colors.transparent);
|
||||||
|
|
||||||
return Stack(
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
spacing: 20,
|
||||||
children: [
|
children: [
|
||||||
Column(
|
Padding(
|
||||||
mainAxisSize: MainAxisSize.max,
|
padding: const EdgeInsets.fromLTRB(15, 0, 50, 0),
|
||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
child: Text(
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
FFLocalizations.of(context).getVariableText(
|
||||||
children: [
|
ptText: 'Suas Categorias',
|
||||||
Padding(
|
enText: 'Your Categories',
|
||||||
padding: const EdgeInsets.fromLTRB(15, 0, 50, 0),
|
|
||||||
child: Text(
|
|
||||||
FFLocalizations.of(context).getVariableText(
|
|
||||||
ptText: 'Suas Categorias',
|
|
||||||
enText: 'Your Categories',
|
|
||||||
),
|
|
||||||
style: TextStyle(
|
|
||||||
color: FlutterFlowTheme.of(context).primaryText,
|
|
||||||
fontSize: LimitedFontSizeUtil.getHeaderFontSize(context),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
FutureBuilder<List<T?>>(
|
style: TextStyle(
|
||||||
future: widget.dataProvider(),
|
color: FlutterFlowTheme.of(context).primaryText,
|
||||||
builder: (context, snapshot) {
|
fontSize: LimitedFontSizeUtil.getHeaderFontSize(context),
|
||||||
if (!snapshot.hasData) return SizedBox();
|
|
||||||
final items = snapshot.data!
|
|
||||||
.map((item) =>
|
|
||||||
widget.itemBuilder(item, itemIsSelected(item as T)))
|
|
||||||
.toList();
|
|
||||||
return SizedBox(
|
|
||||||
height: 130, // Set a specific height
|
|
||||||
child: CarouselView(
|
|
||||||
itemExtent: 140,
|
|
||||||
enableSplash: true,
|
|
||||||
itemSnapping: true,
|
|
||||||
controller: CarouselController(initialItem: 1),
|
|
||||||
backgroundColor: backgroundColor,
|
|
||||||
overlayColor: overlayColor,
|
|
||||||
padding: EdgeInsets.zero,
|
|
||||||
elevation: 0,
|
|
||||||
reverse: true,
|
|
||||||
shrinkExtent: 10,
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(10),
|
|
||||||
),
|
|
||||||
onTap: (index) async {
|
|
||||||
log('Selected: ${snapshot.data![index]}');
|
|
||||||
log('Selected Category: $selectedCategory');
|
|
||||||
final bool isSame =
|
|
||||||
itemIsSelected(snapshot.data![index]!);
|
|
||||||
setState(() {
|
|
||||||
if (isSame) {
|
|
||||||
selectedCategory = null;
|
|
||||||
} else {
|
|
||||||
selectedCategory = snapshot.data![index] as T;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (isSame)
|
|
||||||
widget.filter(null, context);
|
|
||||||
else
|
|
||||||
widget.filter(snapshot.data![index] as T, context);
|
|
||||||
},
|
|
||||||
children: items,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
),
|
),
|
||||||
if (widget.showIndicator)
|
FutureBuilder<List<T?>>(
|
||||||
Positioned(
|
future: dataProvider(),
|
||||||
left: 0,
|
builder: (context, snapshot) {
|
||||||
top: 50,
|
if (!snapshot.hasData) return SizedBox();
|
||||||
child: Icon(Icons.arrow_left, size: 30, color: Colors.grey),
|
final items =
|
||||||
),
|
snapshot.data!.map((item) => itemBuilder(item)).toList();
|
||||||
if (widget.showIndicator)
|
return SizedBox(
|
||||||
Positioned(
|
height: 130, // Set a specific height
|
||||||
right: 0,
|
child: CarouselView(
|
||||||
top: 50,
|
itemExtent: 140,
|
||||||
child: Icon(Icons.arrow_right, size: 30, color: Colors.grey),
|
enableSplash: true,
|
||||||
),
|
itemSnapping: true,
|
||||||
|
controller: CarouselController(initialItem: 1),
|
||||||
|
backgroundColor: backgroundColor,
|
||||||
|
overlayColor: overlayColor,
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
elevation: 0,
|
||||||
|
shrinkExtent: 10,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
),
|
||||||
|
onTap: (index) => filter(snapshot.data![index] as T, context),
|
||||||
|
children: items,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,4 @@
|
||||||
import 'dart:developer';
|
part of 'widgets.dart';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:hub/flutter_flow/index.dart';
|
|
||||||
import 'package:rx_bloc/rx_bloc.dart';
|
|
||||||
import 'package:rx_bloc_list/rx_bloc_list.dart';
|
|
||||||
import 'package:rxdart/rxdart.dart';
|
|
||||||
|
|
||||||
/// [TypeDefs] ----------------------------------------------------
|
/// [TypeDefs] ----------------------------------------------------
|
||||||
|
|
||||||
|
@ -212,10 +206,6 @@ class EnhancedListViewState<ItemType, HeaderType, FooterType, QueryType>
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final String defaultMessage = FFLocalizations.of(context).getVariableText(
|
|
||||||
ptText: 'Nenhum item encontrado',
|
|
||||||
enText: 'No items found',
|
|
||||||
);
|
|
||||||
final header = StreamBuilder<List<HeaderType>>(
|
final header = StreamBuilder<List<HeaderType>>(
|
||||||
stream: bloc.states.headerItems.cast<List<HeaderType>>(),
|
stream: bloc.states.headerItems.cast<List<HeaderType>>(),
|
||||||
builder: (context, headerSnapshot) {
|
builder: (context, headerSnapshot) {
|
||||||
|
@ -255,9 +245,7 @@ class EnhancedListViewState<ItemType, HeaderType, FooterType, QueryType>
|
||||||
} else if (bodySnapshot.hasError) {
|
} else if (bodySnapshot.hasError) {
|
||||||
return EnhancedErrorWidget(error: bodySnapshot.error);
|
return EnhancedErrorWidget(error: bodySnapshot.error);
|
||||||
} else if (!bodySnapshot.hasData || bodySnapshot.data!.isEmpty) {
|
} else if (!bodySnapshot.hasData || bodySnapshot.data!.isEmpty) {
|
||||||
return Center(
|
return const SizedBox.shrink();
|
||||||
child: Text(defaultMessage),
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
return ListView.builder(
|
return ListView.builder(
|
||||||
itemCount: bodySnapshot.data?.length ?? 0,
|
itemCount: bodySnapshot.data?.length ?? 0,
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
part of 'widgets.dart';
|
||||||
|
|
||||||
// class EnhancedSearchView<QueryType> extends StatelessWidget {
|
// class EnhancedSearchView<QueryType> extends StatelessWidget {
|
||||||
// const EnhancedSearchView({
|
// const EnhancedSearchView({
|
||||||
// super.key,
|
// super.key,
|
||||||
|
|
|
@ -1 +1,3 @@
|
||||||
|
part of 'widgets.dart';
|
||||||
|
|
||||||
abstract class Entity<T> {}
|
abstract class Entity<T> {}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
part of 'widgets.dart';
|
||||||
|
|
||||||
// typedef SearchKey = GlobalKey<EnhancedRemoteListViewState>;
|
// typedef SearchKey = GlobalKey<EnhancedRemoteListViewState>;
|
||||||
|
|
||||||
// typedef Query<X extends Archive> = X?;
|
// typedef Query<X extends Archive> = X?;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import 'package:flutter/material.dart';
|
part of 'widgets.dart';
|
||||||
|
|
||||||
class ModelWidget extends Widget {
|
class ModelWidget extends Widget {
|
||||||
const ModelWidget({super.key});
|
const ModelWidget({super.key});
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
import 'package:flutter/widgets.dart';
|
part of 'widgets.dart';
|
||||||
import 'package:hub/shared/mixins/template_mixin.dart';
|
|
||||||
import 'package:hub/shared/widgets.dart';
|
|
||||||
|
|
||||||
/// [PageWidget]
|
/// [PageWidget]
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,6 @@
|
||||||
import 'dart:developer';
|
part of 'widgets.dart';
|
||||||
import 'dart:io';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
// Removed unnecessary import
|
|
||||||
import 'package:hub/flutter_flow/index.dart';
|
|
||||||
import 'package:hub/shared/utils/dialog_util.dart';
|
|
||||||
import 'package:hub/shared/widgets.dart';
|
|
||||||
import 'package:path_provider/path_provider.dart';
|
|
||||||
import 'package:pdfx/pdfx.dart';
|
|
||||||
import 'package:share_plus/share_plus.dart';
|
|
||||||
import 'package:http/http.dart' as http;
|
|
||||||
|
|
||||||
|
// typedef PDFViewerKey = GlobalKey<SfPdfViewerState>;
|
||||||
typedef ReadViewController = PdfController;
|
typedef ReadViewController = PdfController;
|
||||||
typedef DocumentType = PdfDocument;
|
typedef DocumentType = PdfDocument;
|
||||||
|
|
||||||
|
@ -32,11 +23,9 @@ abstract interface class Viewer extends StatelessComponent {
|
||||||
class ReadView extends StatefulWidget {
|
class ReadView extends StatefulWidget {
|
||||||
final String url;
|
final String url;
|
||||||
final String title;
|
final String title;
|
||||||
final VoidCallback onError;
|
|
||||||
|
|
||||||
const ReadView({
|
const ReadView({
|
||||||
super.key,
|
super.key,
|
||||||
required this.onError,
|
|
||||||
required this.url,
|
required this.url,
|
||||||
required this.title,
|
required this.title,
|
||||||
});
|
});
|
||||||
|
@ -47,94 +36,58 @@ class ReadView extends StatefulWidget {
|
||||||
|
|
||||||
class ReadViewState extends State<ReadView> {
|
class ReadViewState extends State<ReadView> {
|
||||||
Future<ReadViewController> _initializePdf() async {
|
Future<ReadViewController> _initializePdf() async {
|
||||||
try {
|
final file = await downloadPdf(widget.url);
|
||||||
final file = await downloadPdf(widget.url);
|
final Future<DocumentType> document = DocumentType.openFile(file.path);
|
||||||
final Future<DocumentType> document = DocumentType.openFile(file.path);
|
return ReadViewController(document: document);
|
||||||
return ReadViewController(document: document);
|
|
||||||
} catch (e) {
|
|
||||||
final message = FFLocalizations.of(context).getVariableText(
|
|
||||||
ptText: 'Erro ao baixar o PDF',
|
|
||||||
enText: 'Error downloading PDF',
|
|
||||||
);
|
|
||||||
|
|
||||||
return Future.error(message);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<File> downloadPdf(String url) async {
|
Future<File> downloadPdf(String url) async {
|
||||||
try {
|
final response = await http.get(Uri.parse(url));
|
||||||
final response = await http.get(Uri.parse(url));
|
if (response.statusCode == 200) {
|
||||||
if (response.statusCode == 200) {
|
final bytes = response.bodyBytes;
|
||||||
final bytes = response.bodyBytes;
|
final dir = await getTemporaryDirectory();
|
||||||
final dir = await getTemporaryDirectory();
|
final file = File('${dir.path}/downloaded.pdf');
|
||||||
final file = File('${dir.path}/downloaded.pdf');
|
await file.writeAsBytes(bytes);
|
||||||
await file.writeAsBytes(bytes);
|
return file;
|
||||||
return file;
|
} else {
|
||||||
} else {
|
throw Exception('Falha ao baixar o PDF');
|
||||||
throw Exception('Falha ao baixar o PDF');
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
final message = FFLocalizations.of(context).getVariableText(
|
|
||||||
ptText: 'Erro ao baixar o PDF',
|
|
||||||
enText: 'Error downloading PDF',
|
|
||||||
);
|
|
||||||
await throwError(message, e);
|
|
||||||
rethrow;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> throwError(String message, dynamic error) async {
|
|
||||||
log('$message: $error');
|
|
||||||
await DialogUtil.error(context, message)
|
|
||||||
.whenComplete(() => widget.onError());
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Stack(
|
return Stack(
|
||||||
children: [
|
children: [
|
||||||
_buildPDFViewer(context),
|
_buildPDFViewer(),
|
||||||
buildShareButton(context),
|
buildShareButton(),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Positioned buildShareButton(BuildContext context) {
|
Positioned buildShareButton() {
|
||||||
final theme = FlutterFlowTheme.of(context);
|
|
||||||
return Positioned(
|
return Positioned(
|
||||||
bottom: 10,
|
bottom: 10,
|
||||||
right: 10,
|
right: 10,
|
||||||
child: IconButton(
|
child: IconButton(
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
Icons.share,
|
Icons.share,
|
||||||
color: theme.primaryText,
|
color: Colors.black,
|
||||||
),
|
),
|
||||||
color: theme.primaryText,
|
color: Colors.black,
|
||||||
onPressed: onShare,
|
onPressed: onShare,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> onShare() async {
|
void onShare() async {
|
||||||
try {
|
final Uri uri = Uri.parse(widget.url);
|
||||||
final Uri uri = Uri.parse(widget.url);
|
final response = await http.get(uri);
|
||||||
final response = await http.get(uri);
|
if (response.statusCode == 200) {
|
||||||
if (response.statusCode == 200) {
|
final XFile xfile = XFile.fromData(response.bodyBytes,
|
||||||
final XFile xfile = XFile.fromData(response.bodyBytes,
|
name: '${widget.title}.pdf', mimeType: 'application/pdf');
|
||||||
name: '${widget.title}.pdf', mimeType: 'application/pdf');
|
await Share.shareXFiles([xfile], text: 'Confira este PDF!');
|
||||||
await Share.shareXFiles([xfile],
|
} else {
|
||||||
text: 'Confira este PDF!',
|
log('Erro ao baixar o arquivo: ${response.statusCode}');
|
||||||
fileNameOverrides: ['${widget.title}.pdf']);
|
|
||||||
} else {
|
|
||||||
throw Exception(
|
|
||||||
'Erro ao compartilhar o arquivo: ${response.statusCode}');
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
final message = FFLocalizations.of(context).getVariableText(
|
|
||||||
ptText: 'Erro ao compartilhar o arquivo',
|
|
||||||
enText: 'Error sharing file',
|
|
||||||
);
|
|
||||||
await throwError(message, e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,19 +104,12 @@ class ReadViewState extends State<ReadView> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildPDFViewer(BuildContext context) => Padding(
|
Widget _buildPDFViewer() => Padding(
|
||||||
padding: EdgeInsets.all(10),
|
padding: EdgeInsets.all(10),
|
||||||
child: FutureBuilder<ReadViewController>(
|
child: FutureBuilder<ReadViewController>(
|
||||||
future: _initializePdf(),
|
future: _initializePdf(),
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
if (!snapshot.hasData) return buildLoadingIndicator(context);
|
if (!snapshot.hasData) return buildLoadingIndicator(context);
|
||||||
if (snapshot.error != null) {
|
|
||||||
return buildLoadingIndicator(context);
|
|
||||||
}
|
|
||||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
|
||||||
return buildLoadingIndicator(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
return PdfView(
|
return PdfView(
|
||||||
controller: snapshot.data!,
|
controller: snapshot.data!,
|
||||||
renderer: (PdfPage page) => page.render(
|
renderer: (PdfPage page) => page.render(
|
||||||
|
@ -180,4 +126,6 @@ class ReadViewState extends State<ReadView> {
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Widget get progressIndicator => LoadingUtil.buildLoadingIndicator(context);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
import 'package:flutter/material.dart';
|
part of 'widgets.dart';
|
||||||
import 'package:hub/shared/mixins/template_mixin.dart';
|
|
||||||
import 'package:hub/shared/widgets.dart';
|
|
||||||
|
|
||||||
abstract class ScreenWidget<T> extends Widget {
|
abstract class ScreenWidget<T> extends Widget {
|
||||||
const ScreenWidget({super.key});
|
const ScreenWidget({super.key});
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import 'package:auto_size_text/auto_size_text.dart';
|
part of 'widgets.dart';
|
||||||
|
|
||||||
class AutoText extends AutoSizeText {
|
class AutoText extends AutoSizeText {
|
||||||
const AutoText(
|
const AutoText(
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
import 'dart:developer';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:auto_size_text/auto_size_text.dart';
|
||||||
|
import 'package:easy_debounce/easy_debounce.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
import 'package:hub/flutter_flow/index.dart';
|
||||||
|
import 'package:hub/shared/mixins/template_mixin.dart';
|
||||||
|
import 'package:hub/shared/utils/index.dart';
|
||||||
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
import 'package:pdfx/pdfx.dart';
|
||||||
|
import 'package:share_plus/share_plus.dart';
|
||||||
|
import 'package:rx_bloc_list/rx_bloc_list.dart';
|
||||||
|
import 'package:rxdart/rxdart.dart';
|
||||||
|
import 'package:rx_bloc/rx_bloc.dart';
|
||||||
|
|
||||||
|
part 'widgets.rxb.g.dart';
|
||||||
|
|
||||||
|
/// [Base]
|
||||||
|
part 'page.dart';
|
||||||
|
part 'component.dart';
|
||||||
|
part 'screen.dart';
|
||||||
|
part 'model.dart';
|
||||||
|
part 'entity.dart';
|
||||||
|
|
||||||
|
/// [View]'s
|
||||||
|
part 'list_view.dart';
|
||||||
|
part 'read_view.dart';
|
||||||
|
part 'enhanced_carousel_view.dart';
|
||||||
|
part 'enhanced_list_view.dart';
|
||||||
|
part 'enhanced_search_view.dart';
|
||||||
|
|
||||||
|
/// [Component]'s
|
||||||
|
part 'text.dart';
|
|
@ -0,0 +1,108 @@
|
||||||
|
// // dart format width=80
|
||||||
|
// // GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
// // **************************************************************************
|
||||||
|
// // Generator: RxBlocGeneratorForAnnotation
|
||||||
|
// // **************************************************************************
|
||||||
|
|
||||||
|
part of 'widgets.dart';
|
||||||
|
|
||||||
|
// /// Used as a contractor for the bloc, events and states classes
|
||||||
|
// /// @nodoc
|
||||||
|
// abstract class EnhancedListViewBlocType extends RxBlocTypeBase {
|
||||||
|
// EnhancedListViewEvents get events;
|
||||||
|
// EnhancedListViewStates get states;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// /// [$EnhancedListViewBloc<BodyType, HeaderType, FooterType, QueryType>] extended by the [EnhancedListViewBloc<BodyType, HeaderType, FooterType, QueryType>]
|
||||||
|
// /// @nodoc
|
||||||
|
// abstract class $EnhancedListViewBloc<BodyType, HeaderType, FooterType, QueryType> extends RxBlocBase
|
||||||
|
// implements
|
||||||
|
// EnhancedListViewEvents,
|
||||||
|
// EnhancedListViewStates,
|
||||||
|
// EnhancedListViewBlocType {
|
||||||
|
// final _compositeSubscription = CompositeSubscription();
|
||||||
|
|
||||||
|
// /// Тhe [Subject] where events sink to by calling [loadBodyItems]
|
||||||
|
// final _$loadBodyItemsEvent = PublishSubject<({bool reset, dynamic query})>();
|
||||||
|
|
||||||
|
// /// Тhe [Subject] where events sink to by calling [loadHeaderItems]
|
||||||
|
// final _$loadHeaderItemsEvent = PublishSubject<void>();
|
||||||
|
|
||||||
|
// /// Тhe [Subject] where events sink to by calling [loadFooterItems]
|
||||||
|
// final _$loadFooterItemsEvent = PublishSubject<void>();
|
||||||
|
|
||||||
|
// /// The state of [bodyItems] implemented in [_mapToBodyItemsState]
|
||||||
|
// late final Stream<List<T>> _bodyItemsState = _mapToBodyItemsState();
|
||||||
|
|
||||||
|
// /// The state of [headerItems] implemented in [_mapToHeaderItemsState]
|
||||||
|
// late final Stream<List<H>> _headerItemsState = _mapToHeaderItemsState();
|
||||||
|
|
||||||
|
// /// The state of [footerItems] implemented in [_mapToFooterItemsState]
|
||||||
|
// late final Stream<List<F>> _footerItemsState = _mapToFooterItemsState();
|
||||||
|
|
||||||
|
// /// The state of [isLoading] implemented in [_mapToIsLoadingState]
|
||||||
|
// late final Stream<bool> _isLoadingState = _mapToIsLoadingState();
|
||||||
|
|
||||||
|
// /// The state of [errors] implemented in [_mapToErrorsState]
|
||||||
|
// late final Stream<String> _errorsState = _mapToErrorsState();
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// void loadBodyItems({
|
||||||
|
// bool reset = false,
|
||||||
|
// dynamic query = null,
|
||||||
|
// }) =>
|
||||||
|
// _$loadBodyItemsEvent.add((
|
||||||
|
// reset: reset,
|
||||||
|
// query: query,
|
||||||
|
// ));
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// void loadHeaderItems() => _$loadHeaderItemsEvent.add(null);
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// void loadFooterItems() => _$loadFooterItemsEvent.add(null);
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// Stream<List<T>> get bodyItems => _bodyItemsState;
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// Stream<List<H>> get headerItems => _headerItemsState;
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// Stream<List<F>> get footerItems => _footerItemsState;
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// Stream<bool> get isLoading => _isLoadingState;
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// Stream<String> get errors => _errorsState;
|
||||||
|
|
||||||
|
// Stream<List<T>> _mapToBodyItemsState();
|
||||||
|
|
||||||
|
// Stream<List<H>> _mapToHeaderItemsState();
|
||||||
|
|
||||||
|
// Stream<List<F>> _mapToFooterItemsState();
|
||||||
|
|
||||||
|
// Stream<bool> _mapToIsLoadingState();
|
||||||
|
|
||||||
|
// Stream<String> _mapToErrorsState();
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// EnhancedListViewEvents get events => this;
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// EnhancedListViewStates get states => this;
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// void dispose() {
|
||||||
|
// _$loadBodyItemsEvent.close();
|
||||||
|
// _$loadHeaderItemsEvent.close();
|
||||||
|
// _$loadFooterItemsEvent.close();
|
||||||
|
// _compositeSubscription.dispose();
|
||||||
|
// super.dispose();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // ignore: unused_element
|
||||||
|
// typedef _LoadBodyItemsEventArgs = ({bool reset, dynamic query});
|
|
@ -3,8 +3,8 @@ name: hub
|
||||||
description: . # Descrição do projeto (adicione mais detalhes se necessário)
|
description: . # Descrição do projeto (adicione mais detalhes se necessário)
|
||||||
publish_to: "none" # Destino de publicação
|
publish_to: "none" # Destino de publicação
|
||||||
|
|
||||||
|
# Versão do aplicativo
|
||||||
version: 1.4.0+28
|
version: 1.3.5+24
|
||||||
|
|
||||||
# Restrições de versão do SDK Dart
|
# Restrições de versão do SDK Dart
|
||||||
environment:
|
environment:
|
||||||
|
@ -113,9 +113,7 @@ dependencies:
|
||||||
url_launcher_platform_interface: 2.3.2
|
url_launcher_platform_interface: 2.3.2
|
||||||
permission_handler: ^11.3.1
|
permission_handler: ^11.3.1
|
||||||
awesome_notifications: ^0.10.0
|
awesome_notifications: ^0.10.0
|
||||||
app_tracking_transparency: ^2.0.6+1
|
app_tracking_transparency: ^2.0.6
|
||||||
# dio: ^5.7.0
|
|
||||||
# crypto: ^3.0.5
|
|
||||||
freezed_annotation: ^2.4.4
|
freezed_annotation: ^2.4.4
|
||||||
package_info_plus: ^8.1.1
|
package_info_plus: ^8.1.1
|
||||||
sliver_tools: ^0.2.12
|
sliver_tools: ^0.2.12
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Define the base URL for the API endpoint
|
|
||||||
BASE_URL="https://freaccess.com.br/freaccess/processRequest.php"
|
|
||||||
|
|
||||||
# Define common parameters
|
|
||||||
DEV_UUID="6b7b81849c115a8a"
|
|
||||||
USER_UUID="678aa05b0c2154.50583237"
|
|
||||||
CLI_ID="7"
|
|
||||||
ACTIVITY="getVehiclesByProperty"
|
|
||||||
PAGE_SIZE="10"
|
|
||||||
|
|
||||||
# Function to perform the HTTP request
|
|
||||||
perform_request() {
|
|
||||||
local page=$1
|
|
||||||
http --form POST "$BASE_URL" \
|
|
||||||
devUUID="$DEV_UUID" \
|
|
||||||
userUUID="$USER_UUID" \
|
|
||||||
cliID="$CLI_ID" \
|
|
||||||
atividade="$ACTIVITY" \
|
|
||||||
page="$page" \
|
|
||||||
pageSize="$PAGE_SIZE" \
|
|
||||||
--check-status \
|
|
||||||
--ignore-stdin \
|
|
||||||
--timeout=10
|
|
||||||
}
|
|
||||||
|
|
||||||
# Perform requests for pages 1 and 2
|
|
||||||
perform_request 1
|
|
||||||
perform_request 2
|
|
|
@ -29,7 +29,7 @@ void main() {
|
||||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
setUpAll(() async {
|
setUpAll(() async {
|
||||||
await initializeBindings();
|
await initializeApp();
|
||||||
});
|
});
|
||||||
|
|
||||||
group('Test', () {
|
group('Test', () {
|
||||||
|
|
Loading…
Reference in New Issue