From 35d683a8ae2eca25970f8280e52e9fd2afbe9a40 Mon Sep 17 00:00:00 2001 From: devmirza121 Date: Mon, 14 Mar 2022 16:14:15 +0300 Subject: [PATCH 1/4] NFC Attendance implement 1.0 --- lib/ui/login/login_screen.dart | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/ui/login/login_screen.dart b/lib/ui/login/login_screen.dart index d5a6061..88caab9 100644 --- a/lib/ui/login/login_screen.dart +++ b/lib/ui/login/login_screen.dart @@ -69,12 +69,12 @@ class _LoginScreenState extends State { } String? firebaseToken; - + GetMobileLoginInfoListModel? loginInfo; Future checkFirebaseToken() async { try { Utils.showLoading(context); firebaseToken = await _firebaseMessaging.getToken(); - GetMobileLoginInfoListModel? loginInfo = await LoginApiClient().getMobileLoginInfoNEW(firebaseToken ?? "", Platform.isAndroid ? "android" : "ios"); + loginInfo = await LoginApiClient().getMobileLoginInfoNEW(firebaseToken ?? "", Platform.isAndroid ? "android" : "ios"); if (loginInfo == null) { Utils.hideLoading(context); print("Device token not found"); @@ -112,7 +112,7 @@ class _LoginScreenState extends State { } Utils.hideLoading(context); if (_autoLogin) { - Navigator.pushNamed(context, AppRoutes.verifyLastLogin); + Navigator.pushNamed(context, AppRoutes.verifyLastLogin, arguments: loginInfo); } else { Navigator.pushNamed(context, AppRoutes.verifyLogin, arguments: "$firebaseToken"); } @@ -125,10 +125,11 @@ class _LoginScreenState extends State { } } + @override Widget build(BuildContext context) { - username.text="15153"; - password.text="Xy12345@"; + username.text = "15153"; + password.text = "Xy12345@"; return Scaffold( body: Column( children: [ From eb3ddb3d9ef47579bf405d83a751739c24da4cc8 Mon Sep 17 00:00:00 2001 From: devmirza121 Date: Sun, 20 Mar 2022 15:58:33 +0300 Subject: [PATCH 2/4] NFC Attendance implement 1.3 --- lib/api/login_api_client.dart | 2 +- lib/ui/landing/today_attendance_screen.dart | 37 ++++++++++++--------- lib/ui/login/login_screen.dart | 3 ++ lib/ui/login/verify_login_screen.dart | 5 ++- 4 files changed, 29 insertions(+), 18 deletions(-) diff --git a/lib/api/login_api_client.dart b/lib/api/login_api_client.dart index 070fa27..2761ebe 100644 --- a/lib/api/login_api_client.dart +++ b/lib/api/login_api_client.dart @@ -79,7 +79,7 @@ class LoginApiClient { Future checkActivationCode(bool isDeviceNFC, String? mobileNumber, String activationCode, String? pUserName) async { String url = "${ApiConsts.erpRest}CheckActivationCode"; - Map postParams = {"isDeviceNFC": isDeviceNFC, "MobileNumber": mobileNumber, "activationCode": activationCode, "P_USER_NAME": pUserName}; + Map postParams = {"IsDeviceNFC": isDeviceNFC, "MobileNumber": mobileNumber, "activationCode": activationCode, "P_USER_NAME": pUserName}; postParams.addAll(AppState().postParamsJson); return await ApiClient().postJsonForObject((json) { GenericResponseModel responseData = GenericResponseModel.fromJson(json); diff --git a/lib/ui/landing/today_attendance_screen.dart b/lib/ui/landing/today_attendance_screen.dart index 2008484..b1ce089 100644 --- a/lib/ui/landing/today_attendance_screen.dart +++ b/lib/ui/landing/today_attendance_screen.dart @@ -46,7 +46,7 @@ class _TodayAttendanceScreenState extends State { bool isAvailable = await NfcManager.instance.isAvailable(); setState(() { AppState().privilegeListModel!.forEach((element) { - // Check availability + print(element.serviceName.toString() + " " + element.previlege.toString()); // Check availability if (isAvailable) if (element.serviceName == "enableNFC") { // if (element.previlege ?? false) isNfcEnabled = true; @@ -190,21 +190,26 @@ class _TodayAttendanceScreenState extends State { gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3, childAspectRatio: 1 / 1, crossAxisSpacing: 8, mainAxisSpacing: 8), children: [ attendanceMethod("NFC", "assets/images/nfc.svg", isNfcEnabled, () { - showNfcReader(context, onNcfScan: (String? nfcId) async { - print(nfcId); - Utils.showLoading(context); - try { - GenericResponseModel? g = await DashboardApiClient().markAttendance(pointType: 2, nfcValue: nfcId ?? ""); - bool status = await model.fetchAttendanceTracking(); - Utils.hideLoading(context); - } catch (ex) { - print(ex); - Utils.hideLoading(context); - Utils.handleException(ex, (msg) { - Utils.confirmDialog(context, msg); - }); - } - }); + if (isNfcLocationEnabled) { + print("nfc location enabled"); + } else { + print("nfc not location enabled"); + } + // showNfcReader(context, onNcfScan: (String? nfcId) async { + // print(nfcId); + // Utils.showLoading(context); + // try { + // GenericResponseModel? g = await DashboardApiClient().markAttendance(pointType: 2, nfcValue: nfcId ?? ""); + // bool status = await model.fetchAttendanceTracking(); + // Utils.hideLoading(context); + // } catch (ex) { + // print(ex); + // Utils.hideLoading(context); + // Utils.handleException(ex, (msg) { + // Utils.confirmDialog(context, msg); + // }); + // } + // }); // Location.getCurrentLocation((LatLng? latlng) { // print(latlng!.longitude.toString()); // }); diff --git a/lib/ui/login/login_screen.dart b/lib/ui/login/login_screen.dart index 88caab9..944a11f 100644 --- a/lib/ui/login/login_screen.dart +++ b/lib/ui/login/login_screen.dart @@ -130,6 +130,9 @@ class _LoginScreenState extends State { Widget build(BuildContext context) { username.text = "15153"; password.text = "Xy12345@"; + + // username.text = "287742"; + // password.text = "509@Shafi"; return Scaffold( body: Column( children: [ diff --git a/lib/ui/login/verify_login_screen.dart b/lib/ui/login/verify_login_screen.dart index 8e9255f..7db2151 100644 --- a/lib/ui/login/verify_login_screen.dart +++ b/lib/ui/login/verify_login_screen.dart @@ -666,7 +666,7 @@ class _VerifyLoginScreenState extends State { (value) async { Utils.showLoading(context); try { - GenericResponseModel? genericResponseModel = await LoginApiClient().checkActivationCode(false, AppState().memberLoginList?.pMOBILENUMBER, value, AppState().getUserName); + GenericResponseModel? genericResponseModel = await LoginApiClient().checkActivationCode(true, AppState().memberLoginList?.pMOBILENUMBER, value, AppState().getUserName); GenericResponseModel? genericResponseModel1 = await LoginApiClient().insertMobileLoginInfoNEW( AppState().memberLoginList?.pEMAILADDRESS ?? "", genericResponseModel?.pSESSIONID ?? 0, @@ -682,6 +682,9 @@ class _VerifyLoginScreenState extends State { AppState().setPrivilegeListModel = genericResponseModel!.privilegeList ?? []; AppState().setMemberInformationListModel = genericResponseModel.memberInformationList?.first; MemberInformationListModel.saveToPrefs(genericResponseModel.memberInformationList ?? []); + genericResponseModel.privilegeList!.forEach((element) { + print(element.serviceName.toString() + " " + element.previlege.toString()); // Check availability + }); PrivilegeListModel.saveToPrefs(genericResponseModel.privilegeList ?? []); Utils.saveStringFromPrefs(SharedPrefsConsts.username, AppState().getUserName!); Utils.saveStringFromPrefs(SharedPrefsConsts.password, AppState().password!); From a4fb526b684d2988d27e4a600aa793ede37f031f Mon Sep 17 00:00:00 2001 From: devmirza121 Date: Wed, 6 Apr 2022 12:22:00 +0300 Subject: [PATCH 3/4] NFC Attendance implement 1.4 --- lib/dialogs/otp_dialog.dart | 1 + lib/ui/landing/today_attendance_screen.dart | 59 ++++++++++++--------- lib/ui/login/login_screen.dart | 2 +- lib/ui/login/verify_last_login_screen.dart | 12 +++++ 4 files changed, 48 insertions(+), 26 deletions(-) diff --git a/lib/dialogs/otp_dialog.dart b/lib/dialogs/otp_dialog.dart index d82cf9c..3789980 100644 --- a/lib/dialogs/otp_dialog.dart +++ b/lib/dialogs/otp_dialog.dart @@ -226,3 +226,4 @@ class OtpDialog { // } } } + diff --git a/lib/ui/landing/today_attendance_screen.dart b/lib/ui/landing/today_attendance_screen.dart index b1ce089..cfba3fd 100644 --- a/lib/ui/landing/today_attendance_screen.dart +++ b/lib/ui/landing/today_attendance_screen.dart @@ -33,7 +33,7 @@ class TodayAttendanceScreen extends StatefulWidget { class _TodayAttendanceScreenState extends State { ValueNotifier result = ValueNotifier(null); late DashboardProviderModel data; - bool isNfcEnabled = false, isNfcLocationEnabled = false, isQrEnabled = false, isQrLocationEnabled = false, isWifiEnabled = false, isWifiLocationEnabled = false; + bool isNfcEnabled = true, isNfcLocationEnabled = false, isQrEnabled = false, isQrLocationEnabled = false, isWifiEnabled = false, isWifiLocationEnabled = false; @override void initState() { @@ -47,14 +47,14 @@ class _TodayAttendanceScreenState extends State { setState(() { AppState().privilegeListModel!.forEach((element) { print(element.serviceName.toString() + " " + element.previlege.toString()); // Check availability - if (isAvailable) if (element.serviceName == "enableNFC") { - // if (element.previlege ?? false) - isNfcEnabled = true; + + if (element.serviceName == "enableNFC") { + if (isAvailable) if (element.previlege ?? false) isNfcEnabled = true; } else if (element.serviceName == "enableQR") { if (element.previlege ?? false) isQrEnabled = true; } else if (element.serviceName == "enableWIFI") { if (element.previlege ?? false) isWifiEnabled = true; - } else if (element.serviceName == "enableLocatoinNFC") { + } else if (element.serviceName!.trim() == "enableLocationNFC") { if (element.previlege ?? false) isNfcLocationEnabled = true; } else if (element.serviceName == "enableLocationQR") { if (element.previlege ?? false) isQrLocationEnabled = true; @@ -191,28 +191,13 @@ class _TodayAttendanceScreenState extends State { children: [ attendanceMethod("NFC", "assets/images/nfc.svg", isNfcEnabled, () { if (isNfcLocationEnabled) { - print("nfc location enabled"); + Location.getCurrentLocation((LatLng? latlng) { + print(latlng!.longitude.toString()); + performNfcAttendance(model, lat: latlng.latitude.toString() ?? "", lng: latlng.longitude.toString() ?? ""); + }); } else { - print("nfc not location enabled"); + performNfcAttendance(model); } - // showNfcReader(context, onNcfScan: (String? nfcId) async { - // print(nfcId); - // Utils.showLoading(context); - // try { - // GenericResponseModel? g = await DashboardApiClient().markAttendance(pointType: 2, nfcValue: nfcId ?? ""); - // bool status = await model.fetchAttendanceTracking(); - // Utils.hideLoading(context); - // } catch (ex) { - // print(ex); - // Utils.hideLoading(context); - // Utils.handleException(ex, (msg) { - // Utils.confirmDialog(context, msg); - // }); - // } - // }); - // Location.getCurrentLocation((LatLng? latlng) { - // print(latlng!.longitude.toString()); - // }); }), attendanceMethod("Wifi", "assets/images/wufu.svg", isWifiEnabled, () {}), ], @@ -249,6 +234,30 @@ class _TodayAttendanceScreenState extends State { ); } + Future performNfcAttendance(DashboardProviderModel model, {String lat = "0", String lng = "0"}) async { + if (isNfcLocationEnabled) { + print("nfc location enabled"); + } else { + print("nfc not location enabled"); + } + + showNfcReader(context, onNcfScan: (String? nfcId) async { + print(nfcId); + Utils.showLoading(context); + try { + GenericResponseModel? g = await DashboardApiClient().markAttendance(pointType: 2, nfcValue: nfcId ?? "", isGpsRequired: isNfcLocationEnabled, lat: lat, long: lng); + bool status = await model.fetchAttendanceTracking(); + Utils.hideLoading(context); + } catch (ex) { + print(ex); + Utils.hideLoading(context); + Utils.handleException(ex, (msg) { + Utils.confirmDialog(context, msg); + }); + } + }); + } + Widget attendanceMethod(String title, String image, bool isEnabled, VoidCallback onPress) => Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(15), diff --git a/lib/ui/login/login_screen.dart b/lib/ui/login/login_screen.dart index 944a11f..ad4e3c2 100644 --- a/lib/ui/login/login_screen.dart +++ b/lib/ui/login/login_screen.dart @@ -75,6 +75,7 @@ class _LoginScreenState extends State { Utils.showLoading(context); firebaseToken = await _firebaseMessaging.getToken(); loginInfo = await LoginApiClient().getMobileLoginInfoNEW(firebaseToken ?? "", Platform.isAndroid ? "android" : "ios"); + loginInfo!.deviceToken = firebaseToken; if (loginInfo == null) { Utils.hideLoading(context); print("Device token not found"); @@ -125,7 +126,6 @@ class _LoginScreenState extends State { } } - @override Widget build(BuildContext context) { username.text = "15153"; diff --git a/lib/ui/login/verify_last_login_screen.dart b/lib/ui/login/verify_last_login_screen.dart index 52ec751..3a7ce86 100644 --- a/lib/ui/login/verify_last_login_screen.dart +++ b/lib/ui/login/verify_last_login_screen.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:easy_localization/src/public_ext.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -246,6 +248,16 @@ class _VerifyLastLoginScreenState extends State { Utils.showLoading(context); try { GenericResponseModel? genericResponseModel = await LoginApiClient().checkActivationCode(false, AppState().memberLoginList?.pMOBILENUMBER, value, AppState().getUserName); + GenericResponseModel? genericResponseModel1 = await LoginApiClient().insertMobileLoginInfoNEW( + AppState().memberLoginList?.pEMAILADDRESS ?? "", + genericResponseModel?.pSESSIONID ?? 0, + genericResponseModel?.memberInformationList![0].eMPLOYEENAME ?? "", + _flag, + AppState().memberLoginList?.pMOBILENUMBER ?? "", + AppState().getUserName!, + mobileLoginInfoListModel!.deviceToken!, + Platform.isAndroid ? "android" : "ios"); + if (genericResponseModel?.errorMessage != null) { Utils.showToast(genericResponseModel?.errorMessage ?? ""); // Navigator.pop(context); From 9b5147b565a73533ca6e39d47bd6b241cef4acf8 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Tue, 10 May 2022 17:38:19 +0300 Subject: [PATCH 4/4] merge improvements --- lib/api/api_client.dart | 6 +++++- lib/app_state/app_state.dart | 4 ++++ lib/classes/utils.dart | 5 +++-- lib/provider/dashboard_provider_model.dart | 4 ++-- lib/ui/landing/dashboard_screen.dart | 2 +- lib/ui/landing/today_attendance_screen.dart | 11 +++++------ lib/ui/login/login_screen.dart | 4 +--- .../missing_swipe/fragments/info_fragments.dart | 4 ++-- 8 files changed, 23 insertions(+), 17 deletions(-) diff --git a/lib/api/api_client.dart b/lib/api/api_client.dart index 17eac0d..3263bf4 100644 --- a/lib/api/api_client.dart +++ b/lib/api/api_client.dart @@ -5,6 +5,7 @@ import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:http/http.dart'; import 'package:http/io_client.dart'; +import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/exceptions/api_exception.dart'; import '../main.dart'; @@ -81,6 +82,9 @@ class ApiClient { logger.i("res: " + response.body); } var jsonData = jsonDecode(response.body); + if (jsonData["IsAuthenticated"] != null) { + AppState().setIsAuthenticated = jsonData["IsAuthenticated"]; + } if (jsonData["ErrorMessage"] == null) { return factoryConstructor(jsonData); } else { @@ -237,4 +241,4 @@ class ApiClient { } Future _post(url, {Map? headers, body, Encoding? encoding}) => _withClient((client) => client.post(url, headers: headers, body: body, encoding: encoding)); - } +} diff --git a/lib/app_state/app_state.dart b/lib/app_state/app_state.dart index 51337ff..de05b56 100644 --- a/lib/app_state/app_state.dart +++ b/lib/app_state/app_state.dart @@ -12,6 +12,10 @@ class AppState { factory AppState() => _instance; + bool isAuthenticated = false; + + set setIsAuthenticated(v) => isAuthenticated = v; + bool isLogged = false; set setLogged(v) => isLogged = v; diff --git a/lib/classes/utils.dart b/lib/classes/utils.dart index d3081d4..1634fd5 100644 --- a/lib/classes/utils.dart +++ b/lib/classes/utils.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:fluttertoast/fluttertoast.dart'; +import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/config/routes.dart'; // import 'package:fluttertoast/fluttertoast.dart'; @@ -83,12 +84,12 @@ class Utils { if (onErrorMessage != null) { onErrorMessage(errorMessage); } else { - if (errorMessage.contains("User session is not valid")) { + if (!AppState().isAuthenticated) { showDialog( context: cxt, builder: (cxt) => ConfirmDialog( message: errorMessage, - onTap: (){ + onTap: () { Navigator.pushNamedAndRemoveUntil(cxt, AppRoutes.login, (Route route) => false); }, ), diff --git a/lib/provider/dashboard_provider_model.dart b/lib/provider/dashboard_provider_model.dart index 61b66c6..9316182 100644 --- a/lib/provider/dashboard_provider_model.dart +++ b/lib/provider/dashboard_provider_model.dart @@ -71,8 +71,8 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { return ((hour * 60 * 60) + (mints * 60) + seconds); } - update() { - fetchAttendanceTracking(); + update(context) { + fetchAttendanceTracking(context); // isAttendanceTrackingLoading = !isAttendanceTrackingLoading; // isWorkListLoading = !isWorkListLoading; // attendanceTracking?.pSwipeIn = "a"; diff --git a/lib/ui/landing/dashboard_screen.dart b/lib/ui/landing/dashboard_screen.dart index 4d9fdef..029da02 100644 --- a/lib/ui/landing/dashboard_screen.dart +++ b/lib/ui/landing/dashboard_screen.dart @@ -96,7 +96,7 @@ class _DashboardScreenState extends State { ], ), ).onPress(() { - data.update(); + data.update(context); }) ], ).paddingOnly(left: 21, right: 21, top: 48, bottom: 7), diff --git a/lib/ui/landing/today_attendance_screen.dart b/lib/ui/landing/today_attendance_screen.dart index cfba3fd..6268425 100644 --- a/lib/ui/landing/today_attendance_screen.dart +++ b/lib/ui/landing/today_attendance_screen.dart @@ -42,7 +42,7 @@ class _TodayAttendanceScreenState extends State { data = Provider.of(context, listen: false); } - checkAttendanceAvailablity() async { + void checkAttendanceAvailablity() async { bool isAvailable = await NfcManager.instance.isAvailable(); setState(() { AppState().privilegeListModel!.forEach((element) { @@ -84,7 +84,7 @@ class _TodayAttendanceScreenState extends State { actions: [ IconButton( onPressed: () { - data.fetchAttendanceTracking(); + data.fetchAttendanceTracking(context); }, icon: Icon( Icons.ac_unit, @@ -192,8 +192,7 @@ class _TodayAttendanceScreenState extends State { attendanceMethod("NFC", "assets/images/nfc.svg", isNfcEnabled, () { if (isNfcLocationEnabled) { Location.getCurrentLocation((LatLng? latlng) { - print(latlng!.longitude.toString()); - performNfcAttendance(model, lat: latlng.latitude.toString() ?? "", lng: latlng.longitude.toString() ?? ""); + performNfcAttendance(model, lat: latlng?.latitude.toString() ?? "", lng: latlng?.longitude.toString() ?? ""); }); } else { performNfcAttendance(model); @@ -246,12 +245,12 @@ class _TodayAttendanceScreenState extends State { Utils.showLoading(context); try { GenericResponseModel? g = await DashboardApiClient().markAttendance(pointType: 2, nfcValue: nfcId ?? "", isGpsRequired: isNfcLocationEnabled, lat: lat, long: lng); - bool status = await model.fetchAttendanceTracking(); + bool status = await model.fetchAttendanceTracking(context); Utils.hideLoading(context); } catch (ex) { print(ex); Utils.hideLoading(context); - Utils.handleException(ex, (msg) { + Utils.handleException(ex, context, (msg) { Utils.confirmDialog(context, msg); }); } diff --git a/lib/ui/login/login_screen.dart b/lib/ui/login/login_screen.dart index 9b09023..29fbbfe 100644 --- a/lib/ui/login/login_screen.dart +++ b/lib/ui/login/login_screen.dart @@ -75,18 +75,16 @@ class _LoginScreenState extends State { Utils.showLoading(context); firebaseToken = await _firebaseMessaging.getToken(); loginInfo = await LoginApiClient().getMobileLoginInfoNEW(firebaseToken ?? "", Platform.isAndroid ? "android" : "ios"); - loginInfo!.deviceToken = firebaseToken; if (loginInfo == null) { Utils.hideLoading(context); - print("Device token not found"); return; } else { + loginInfo!.deviceToken = firebaseToken; await checkPrefs(); Utils.hideLoading(context); performLogin(); } } catch (ex) { - print(ex); Utils.hideLoading(context); Utils.handleException(ex, context, null); } diff --git a/lib/ui/work_list/missing_swipe/fragments/info_fragments.dart b/lib/ui/work_list/missing_swipe/fragments/info_fragments.dart index df883c8..ba0e57e 100644 --- a/lib/ui/work_list/missing_swipe/fragments/info_fragments.dart +++ b/lib/ui/work_list/missing_swipe/fragments/info_fragments.dart @@ -165,13 +165,13 @@ class InfoFragment extends StatelessWidget { ItemDetailView(LocaleKeys.operatingUnit.tr(), itemCreationHeader[index].oPERATINGUNIT?.toString() ?? ""), ItemDetailView(LocaleKeys.category.tr(), itemCreationHeader[index].cATEGORY?.toString() ?? ""), ItemDetailView(LocaleKeys.requester.tr(), itemCreationHeader[index].rEQUESTER?.toString() ?? ""), - ItemDetailView(LocaleKeys.analyzedBy.tr(), itemCreationHeader[index].aNALYZEDBY.toString() ?? ""), + ItemDetailView(LocaleKeys.analyzedBy.tr(), itemCreationHeader[index].aNALYZEDBY?.toString() ?? ""), ItemDetailView(LocaleKeys.approvedDate.tr(), itemCreationHeader[index].aPPROVEDDATE?.toString() ?? ""), ItemDetailView(LocaleKeys.itemType.tr(), itemCreationHeader[index].iTEMTYPE?.toString() ?? ""), ItemDetailView(LocaleKeys.relatedTo.tr(), itemCreationHeader[index].rELATEDTO?.toString() ?? ""), ItemDetailView(LocaleKeys.requestDate.tr(), DateUtil.formatDateToDate(DateUtil.convertStringToDate(itemCreationHeader[index].rEQUESTDATE.toString()), false) ?? ""), ItemDetailView(LocaleKeys.analyzedDate.tr(), itemCreationHeader[index].aNALYZEDDATE?.toString() ?? ""), - ItemDetailView(LocaleKeys.urgent.tr(), itemCreationHeader[index].uRGENTFLAGDISP.toString() ?? ""), + ItemDetailView(LocaleKeys.urgent.tr(), itemCreationHeader[index].uRGENTFLAGDISP?.toString() ?? ""), ], ).objectContainerView(), separatorBuilder: (cxt, index) => 18.height,