diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 8d53eaf..7be27d5 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -2,6 +2,9 @@ package="com.mohem_flutter_app"> + + + diff --git a/assets/icons/create_req.svg b/assets/icons/create_req.svg new file mode 100644 index 0000000..a87e809 --- /dev/null +++ b/assets/icons/create_req.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/assets/icons/home.svg b/assets/icons/home.svg new file mode 100644 index 0000000..fb67997 --- /dev/null +++ b/assets/icons/home.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/assets/icons/item_for_sale.svg b/assets/icons/item_for_sale.svg new file mode 100644 index 0000000..0a87567 --- /dev/null +++ b/assets/icons/item_for_sale.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/icons/nfc/ic_done.png b/assets/icons/nfc/ic_done.png new file mode 100644 index 0000000..5b80285 Binary files /dev/null and b/assets/icons/nfc/ic_done.png differ diff --git a/assets/icons/nfc/ic_nfc.png b/assets/icons/nfc/ic_nfc.png new file mode 100644 index 0000000..274e1b8 Binary files /dev/null and b/assets/icons/nfc/ic_nfc.png differ diff --git a/assets/icons/work_list.svg b/assets/icons/work_list.svg new file mode 100644 index 0000000..a802c53 --- /dev/null +++ b/assets/icons/work_list.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/lib/api/dashboard_api_client.dart b/lib/api/dashboard_api_client.dart index 76e2453..f4c583d 100644 --- a/lib/api/dashboard_api_client.dart +++ b/lib/api/dashboard_api_client.dart @@ -8,6 +8,7 @@ import 'package:mohem_flutter_app/models/dashboard/get_attendance_tracking_list_ import 'package:mohem_flutter_app/models/dashboard/itg_forms_model.dart'; import 'package:mohem_flutter_app/models/generic_response_model.dart'; import 'package:mohem_flutter_app/models/member_login_list_model.dart'; +import 'package:uuid/uuid.dart'; import 'api_client.dart'; @@ -89,4 +90,27 @@ class DashboardApiClient { return responseData; }, url, postParams); } + + //Mark Attendance + Future markAttendance({String lat = "0", String? long = "0", required int pointType, String nfcValue = "", bool isGpsRequired = false}) async { + String url = "${ApiConsts.swpRest}AuthenticateAndSwipeUserSupportNFC"; + var uuid = Uuid(); + // Generate a v4 (random) id + + Map postParams = { + "UID": uuid.v4(), //Mobile Id + "Latitude": lat, + "Longitude": long, + "QRValue": "", + "PointType": pointType, // NFC=2, Wifi = 3, QR= 1, + "NFCValue": nfcValue, + "WifiValue": "", + "IsGpsRequired": isGpsRequired + }; + postParams.addAll(AppState().postParamsJson); + return await ApiClient().postJsonForObject((json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData; + }, url, postParams); + } } diff --git a/lib/app_state/app_state.dart b/lib/app_state/app_state.dart index 89493ee..51337ff 100644 --- a/lib/app_state/app_state.dart +++ b/lib/app_state/app_state.dart @@ -37,6 +37,7 @@ class AppState { bool isArabic(context) => EasyLocalization.of(context)?.locale.languageCode == "ar"; String? _username; + // todo ''sikander' added password for now, later will remove & improve String? password; diff --git a/lib/classes/app_permissions.dart b/lib/classes/app_permissions.dart new file mode 100644 index 0000000..a70342c --- /dev/null +++ b/lib/classes/app_permissions.dart @@ -0,0 +1,30 @@ +import 'package:permission_handler/permission_handler.dart'; + +class AppPermissions{ + static location(Function(bool) completion) { + Permission.location.isGranted.then((isGranted){ + if(!isGranted){ + Permission.location.request().then((granted){ + completion(granted == PermissionStatus.granted); + }); + } + completion(isGranted); + }); + + } + + static checkAll(Function(bool) completion){ + [ + Permission.location + ].request().then((value){ + + bool allGranted = false; + value.values.forEach((element) { + allGranted = allGranted && element == PermissionStatus.granted; + }); + + completion(allGranted); + + }); + } +} \ No newline at end of file diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index a11edec..a95e5b4 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -1,10 +1,12 @@ class ApiConsts { //static String baseUrl = "http://10.200.204.20:2801/"; // Local server static String baseUrl = "https://uat.hmgwebservices.com"; // UAT server - static String baseUrlServices = baseUrl + "/services/"; // server + // static String baseUrl = "https://hmgwebservices.com"; // Live server + static String baseUrlServices = baseUrl + "/Services/"; // server // static String baseUrlServices = "https://api.cssynapses.com/tangheem/"; // Live server static String utilitiesRest = baseUrlServices + "Utilities.svc/REST/"; static String erpRest = baseUrlServices + "ERP.svc/REST/"; + static String swpRest = baseUrlServices + "SWP.svc/REST/"; static String user = baseUrlServices + "api/User/"; static String cocRest = baseUrlServices + "COCWS.svc/REST/"; } diff --git a/lib/classes/utils.dart b/lib/classes/utils.dart index 3b200f5..d3081d4 100644 --- a/lib/classes/utils.dart +++ b/lib/classes/utils.dart @@ -47,6 +47,10 @@ class Utils { }); } + static Future delay(int millis) async { + return await Future.delayed(Duration(milliseconds: millis)); + } + static void hideLoading(BuildContext context) { if (_isLoadingVisible) { _isLoadingVisible = false; diff --git a/lib/main.dart b/lib/main.dart index 6a0516e..9952762 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,4 +1,5 @@ import 'dart:io'; +import 'dart:typed_data'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; @@ -9,6 +10,9 @@ import 'package:mohem_flutter_app/models/post_params_model.dart'; import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart'; import 'package:mohem_flutter_app/provider/eit_provider_model.dart'; import 'package:mohem_flutter_app/theme/app_theme.dart'; +import 'package:mohem_flutter_app/widgets/nfc/nfc_reader_sheet.dart'; +import 'package:nfc_manager/nfc_manager.dart'; +import 'package:nfc_manager/platform_tags.dart'; import 'package:provider/provider.dart'; import 'package:sizer/sizer.dart'; import 'package:firebase_core/firebase_core.dart'; @@ -26,7 +30,7 @@ Future main() async { await EasyLocalization.ensureInitialized(); await Firebase.initializeApp(); AppState().setPostParamsModel( - PostParamsModel(channel: 31, versionID: 3.2, mobileType: Platform.isAndroid ? "android" : "ios"), + PostParamsModel(channel: 31, versionID: 3.4, mobileType: Platform.isAndroid ? "android" : "ios"), ); runApp( EasyLocalization( @@ -79,3 +83,140 @@ class MyApp extends StatelessWidget { ); } } + +// class MyApp extends StatefulWidget { +// @override +// State createState() => MyAppState(); +// } +// +// class MyAppState extends State { +// ValueNotifier result = ValueNotifier(null); +// +// @override +// Widget build(BuildContext context) { +// return MaterialApp( +// home: Scaffold( +// appBar: AppBar(title: Text('NfcManager Plugin Example')), +// body: SafeArea( +// child: FutureBuilder( +// future: NfcManager.instance.isAvailable(), +// builder: (context, ss) => ss.data != true +// ? Center(child: Text('NfcManager.isAvailable(): ${ss.data}')) +// : Flex( +// mainAxisAlignment: MainAxisAlignment.spaceBetween, +// direction: Axis.vertical, +// children: [ +// Flexible( +// flex: 2, +// child: Container( +// margin: EdgeInsets.all(4), +// constraints: BoxConstraints.expand(), +// decoration: BoxDecoration(border: Border.all()), +// child: SingleChildScrollView( +// child: ValueListenableBuilder( +// valueListenable: result, +// builder: (context, value, _) => Text('${value ?? ''}'), +// ), +// ), +// ), +// ), +// Flexible( +// flex: 3, +// child: GridView.count( +// padding: EdgeInsets.all(4), +// crossAxisCount: 2, +// childAspectRatio: 4, +// crossAxisSpacing: 4, +// mainAxisSpacing: 4, +// children: [ +// ElevatedButton(child: Text('Tag Read'), onPressed: _tagRead), +// ElevatedButton(child: Text('Ndef Write'), onPressed: _ndefWrite), +// ElevatedButton(child: Text('Ndef Write Lock'), onPressed: _ndefWriteLock), +// ], +// ), +// ), +// ], +// ), +// ), +// ), +// ), +// ); +// } +// +// void _tagRead() { +// showNfcReader( +// context, +// onNcfScan: (String? nfcId) {}, +// ); +// // NfcManager.instance.startSession(onDiscovered: (NfcTag tag) async { +// // result.value = tag.data; +// // print(tag.data); +// // var ndef = Ndef.from(tag); +// // +// // var f = MifareUltralight(tag: tag, identifier: tag.data["nfca"]["identifier"], type: 2, maxTransceiveLength: 252, timeout: 22); +// // final String identifier = f.identifier.map((e) => e.toRadixString(16).padLeft(2, '0')).join(''); +// // print(identifier); // => 0428fcf2255e81 +// // print(ndef!.additionalData); +// // +// // // onDiscovered callback +// // // final mifare = MiFare.from(tag); +// // // if (mifare == null) { +// // // print('Tag is not compatible with MiFare.'); +// // // return; +// // // } +// // // print(mifare.identifier); +// // // final String identifier = mifare.identifier.map((e) => e.toRadixString(16).padLeft(2, '0')).join(''); +// // // print(identifier); // => 0428fcf2255e81 +// // NfcManager.instance.stopSession(); +// // }); +// } +// +// void _ndefWrite() { +// NfcManager.instance.startSession(onDiscovered: (NfcTag tag) async { +// var ndef = Ndef.from(tag); +// if (ndef == null || !ndef.isWritable) { +// result.value = 'Tag is not ndef writable'; +// NfcManager.instance.stopSession(errorMessage: result.value); +// return; +// } +// +// NdefMessage message = NdefMessage([ +// NdefRecord.createText('Hello World!'), +// NdefRecord.createUri(Uri.parse('https://flutter.dev')), +// NdefRecord.createMime('text/plain', Uint8List.fromList('Hello'.codeUnits)), +// NdefRecord.createExternal('com.example', 'mytype', Uint8List.fromList('mydata'.codeUnits)), +// ]); +// +// try { +// await ndef.write(message); +// result.value = 'Success to "Ndef Write"'; +// NfcManager.instance.stopSession(); +// } catch (e) { +// result.value = e; +// NfcManager.instance.stopSession(errorMessage: result.value.toString()); +// return; +// } +// }); +// } +// +// void _ndefWriteLock() { +// NfcManager.instance.startSession(onDiscovered: (NfcTag tag) async { +// var ndef = Ndef.from(tag); +// if (ndef == null) { +// result.value = 'Tag is not ndef'; +// NfcManager.instance.stopSession(errorMessage: result.value.toString()); +// return; +// } +// +// try { +// await ndef.writeLock(); +// result.value = 'Success to "Ndef Write Lock"'; +// NfcManager.instance.stopSession(); +// } catch (e) { +// result.value = e; +// NfcManager.instance.stopSession(errorMessage: result.value.toString()); +// return; +// } +// }); +// } +// } diff --git a/lib/provider/dashboard_provider_model.dart b/lib/provider/dashboard_provider_model.dart index 9fab4b9..9316182 100644 --- a/lib/provider/dashboard_provider_model.dart +++ b/lib/provider/dashboard_provider_model.dart @@ -19,6 +19,7 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { //Attendance Tracking bool isAttendanceTrackingLoading = true; int endTime = 0, isTimeRemainingInSeconds = 0; + double progress = 0.0; GetAttendanceTracking? attendanceTracking; //Work List @@ -40,19 +41,27 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { List? getMenuEntriesList; //Attendance Tracking API's & Methods - void fetchAttendanceTracking(context) async { + Future fetchAttendanceTracking(context) async { try { attendanceTracking = await DashboardApiClient().getAttendanceTracking(); + print("attendanceTracking:" + (attendanceTracking!.pRemainingHours).toString()); isAttendanceTrackingLoading = false; - isTimeRemainingInSeconds = calculateSeconds("00:00:00"); - endTime = DateTime.now().millisecondsSinceEpoch + Duration(seconds: isTimeRemainingInSeconds).inMilliseconds; - print("isTimeRemainingInSeconds " + isTimeRemainingInSeconds.toString()); - print("endTime " + endTime.toString()); + // isTimeRemainingInSeconds = calculateSeconds( "00:00:00"); + if (attendanceTracking?.pSwipeIn != null) { + isTimeRemainingInSeconds = calculateSeconds(attendanceTracking!.pRemainingHours ?? "00:00:00"); + int totalShiftTimeInSeconds = calculateSeconds(attendanceTracking!.pScheduledHours ?? "00:00:00"); + print("totalShiftTimeInSeconds: " + totalShiftTimeInSeconds.toString()); + print("isTimeRemainingInSeconds: " + isTimeRemainingInSeconds.toString()); + progress = (isTimeRemainingInSeconds / totalShiftTimeInSeconds); + endTime = DateTime.now().millisecondsSinceEpoch + Duration(seconds: isTimeRemainingInSeconds).inMilliseconds; + print("endTime " + endTime.toString()); + } - // notifyListeners(); + notifyListeners(); } catch (ex) { Utils.handleException(ex, context, null); } + return true; } int calculateSeconds(String time) { @@ -62,17 +71,19 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { return ((hour * 60 * 60) + (mints * 60) + seconds); } - update() { - isAttendanceTrackingLoading = !isAttendanceTrackingLoading; - isWorkListLoading = !isWorkListLoading; - attendanceTracking?.pSwipeIn = "a"; - isTimeRemainingInSeconds = calculateSeconds("00:10:30"); - endTime = DateTime.now().millisecondsSinceEpoch + Duration(seconds: isTimeRemainingInSeconds).inMilliseconds; - notifyListeners(); + update(context) { + fetchAttendanceTracking(context); + // isAttendanceTrackingLoading = !isAttendanceTrackingLoading; + // isWorkListLoading = !isWorkListLoading; + // attendanceTracking?.pSwipeIn = "a"; + // isTimeRemainingInSeconds = calculateSeconds("00:10:30"); + // endTime = DateTime.now().millisecondsSinceEpoch + Duration(seconds: isTimeRemainingInSeconds).inMilliseconds; + // notifyListeners(); } ItgFormsModel? itgFormsModel; List? getOpenNotificationsList; + //Work List API's & Methods Future fetchWorkListCounter(context, {bool showLoading = false}) async { try { @@ -167,7 +178,7 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { } } - //Verify Menus by printing in log + // Verify Menus by printing in log // for(int i=0;i { data.fetchWorkListCounter(context); data.fetchMissingSwipe(context); data.fetchLeaveTicketBalance(context); - data.fetchMenuEntries(); + // data.fetchMenuEntries(); } @override @@ -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 b2ab7aa..2008484 100644 --- a/lib/ui/landing/today_attendance_screen.dart +++ b/lib/ui/landing/today_attendance_screen.dart @@ -1,12 +1,25 @@ import 'package:easy_localization/src/public_ext.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_countdown_timer/flutter_countdown_timer.dart'; import 'package:flutter_svg/flutter_svg.dart'; +import 'package:google_maps_flutter/google_maps_flutter.dart'; +import 'package:mohem_flutter_app/api/dashboard_api_client.dart'; +import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/classes/colors.dart'; +import 'package:mohem_flutter_app/classes/date_uitl.dart'; +import 'package:mohem_flutter_app/classes/utils.dart'; import 'package:mohem_flutter_app/extensions/int_extensions.dart'; import 'package:mohem_flutter_app/extensions/string_extensions.dart'; import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; +import 'package:mohem_flutter_app/models/generic_response_model.dart'; import 'package:mohem_flutter_app/widgets/circular_step_progress_bar.dart'; +import 'package:mohem_flutter_app/widgets/nfc/nfc_reader_sheet.dart'; +import 'package:nfc_manager/nfc_manager.dart'; +import 'package:provider/provider.dart'; + +import '../../provider/dashboard_provider_model.dart'; +import '../../widgets/location/Location.dart'; class TodayAttendanceScreen extends StatefulWidget { TodayAttendanceScreen({Key? key}) : super(key: key); @@ -18,14 +31,45 @@ 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; + @override void initState() { super.initState(); + checkAttendanceAvailablity(); + data = Provider.of(context, listen: false); + } + + checkAttendanceAvailablity() async { + bool isAvailable = await NfcManager.instance.isAvailable(); + setState(() { + AppState().privilegeListModel!.forEach((element) { + // Check availability + if (isAvailable) if (element.serviceName == "enableNFC") { + // 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") { + if (element.previlege ?? false) isNfcLocationEnabled = true; + } else if (element.serviceName == "enableLocationQR") { + if (element.previlege ?? false) isQrLocationEnabled = true; + } else if (element.serviceName == "enableLocationWIFI") { + if (element.previlege ?? false) isWifiLocationEnabled = true; + } + }); + }); } @override void dispose() { super.dispose(); + // Stop Session + NfcManager.instance.stopSession(); } @override @@ -37,123 +81,170 @@ class _TodayAttendanceScreenState extends State { icon: const Icon(Icons.arrow_back_ios, color: Colors.white), onPressed: () => Navigator.pop(context), ), - ), - backgroundColor: Colors.white, - body: ListView( - children: [ - Container( - color: MyColors.backgroundBlackColor, - padding: EdgeInsets.only(top: 4,left: 21, right: 21, bottom: 21), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - "June 13, 2021".toText24(isBold: true, color: Colors.white), - LocaleKeys.timeLeftToday.tr().toText16(color: Color(0xffACACAC)), - 21.height, - Center( - child: CircularStepProgressBar( - totalSteps: 16 * 4, - currentStep: 16, - width: 216, - height: 216, - selectedColor: MyColors.gradiantEndColor, - unselectedColor: MyColors.grey70Color, - child: Center( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - "08:58:15".toText32(color: Colors.white, isBold: true), - 19.height, - "Shift Time".tr().toText12(color: MyColors.greyACColor), - "08:00 - 17:00".toText22(color: Colors.white, isBold: true), - ], - ), - ), - ), - ), - ], - ), - ), - Container( - color: MyColors.backgroundBlackColor, - child: Stack( - children: [ - Container( - height: 187, - padding: EdgeInsets.only(left: 31, right: 31, top: 31, bottom: 16), - decoration: BoxDecoration( - borderRadius: BorderRadius.only(topLeft: Radius.circular(25), topRight: Radius.circular(25)), - gradient: const LinearGradient(transform: GradientRotation(.64), begin: Alignment.topRight, end: Alignment.bottomLeft, colors: [ - MyColors.gradiantEndColor, - MyColors.gradiantStartColor, - ]), - ), - child: Column( - children: [ - Row( - children: [commonStatusView("Check In", "09:27"), commonStatusView("Check Out", "- - : - -")], - ), - 21.height, - Row( - children: [commonStatusView("Late In", "00:27"), commonStatusView("Regular", "08:00")], - ), - ], - ), - ), - Container( - width: double.infinity, - decoration: BoxDecoration(borderRadius: BorderRadius.only(topLeft: Radius.circular(25), topRight: Radius.circular(25)), color: Colors.white), - margin: EdgeInsets.only(top: 187 - 31), - padding: EdgeInsets.only(left: 21, right: 21, top: 24, bottom: 24), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - "Mark".tr().toText12(), - "Attendance".tr().toText24(), - "Select the method to mark the attendance".tr().toText12(color: Color(0xff535353)), - 24.height, - GridView( - physics: const NeverScrollableScrollPhysics(), - shrinkWrap: true, - padding: EdgeInsets.zero, - gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3, childAspectRatio: 1 / 1, crossAxisSpacing: 8, mainAxisSpacing: 8), - children: [ - attendanceMethod("NFC", "assets/images/nfc.svg", () {}), - attendanceMethod("Wifi", "assets/images/wufu.svg", () {}), - ], - ) - ], - ), - ), - // Positioned( - // top: 187 - 21, - // child: Container( - // padding: EdgeInsets.only(left: 31, right: 31, top: 31, bottom: 16), - // decoration: BoxDecoration(borderRadius: BorderRadius.only(topLeft: Radius.circular(25), topRight: Radius.circular(25)), color: Colors.white), - // child: Column( - // children: [ - // Row( - // children: [commonStatusView("Check In", "09:27"), commonStatusView("Check Out", "- - : - -")], - // ), - // 21.height, - // Row( - // children: [commonStatusView("Late In", "00:27"), commonStatusView("Regular", "08:00")], - // ), - // ], - // ), - // ), - // ), - ], + actions: [ + IconButton( + onPressed: () { + data.fetchAttendanceTracking(); + }, + icon: Icon( + Icons.ac_unit, + color: Colors.white, ), ) ], ), + backgroundColor: MyColors.backgroundBlackColor, + body: Consumer( + builder: (context, model, child) { + return (model.isAttendanceTrackingLoading + ? Center(child: CircularProgressIndicator()) + : ListView( + children: [ + Container( + color: MyColors.backgroundBlackColor, + padding: EdgeInsets.only(top: 4, left: 21, right: 21, bottom: 21), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + DateUtil.getWeekDayMonthDayYearDateFormatted(DateTime.now(), "en").toText24(isBold: true, color: Colors.white), + LocaleKeys.timeLeftToday.tr().toText16(color: Color(0xffACACAC)), + 21.height, + Center( + child: CircularStepProgressBar( + totalSteps: 16 * 4, + currentStep: (model.progress * 100).toInt(), + width: 216, + height: 216, + selectedColor: MyColors.gradiantEndColor, + unselectedColor: MyColors.grey70Color, + child: Center( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + CountdownTimer( + endTime: model.endTime, + onEnd: null, + endWidget: "00:00:00".toText32(color: Colors.white, isBold: true), + textStyle: TextStyle(color: Colors.white, fontSize: 32, letterSpacing: -1.92, fontWeight: FontWeight.bold, height: 1), + ), + 19.height, + "Shift Time".tr().toText12(color: MyColors.greyACColor), + (model.attendanceTracking!.pShtName ?? "00:00:00").toString().toText22(color: Colors.white, isBold: true), + ], + ), + ), + ), + ), + ], + ), + ), + Container( + color: MyColors.backgroundBlackColor, + child: Stack( + children: [ + Container( + height: 187, + padding: EdgeInsets.only(left: 31, right: 31, top: 31, bottom: 16), + decoration: BoxDecoration( + borderRadius: BorderRadius.only(topLeft: Radius.circular(25), topRight: Radius.circular(25)), + gradient: const LinearGradient(transform: GradientRotation(.64), begin: Alignment.topRight, end: Alignment.bottomLeft, colors: [ + MyColors.gradiantEndColor, + MyColors.gradiantStartColor, + ]), + ), + child: Column( + children: [ + Row( + children: [ + commonStatusView("Check In", (model.attendanceTracking!.pSwipeIn) ?? "- - : - -"), + commonStatusView("Check Out", (model.attendanceTracking!.pSwipeOut) ?? "- - : - -") + ], + ), + 21.height, + Row( + children: [ + commonStatusView("Late In", (model.attendanceTracking!.pLateInHours) ?? "- - : - -"), + commonStatusView("Regular", (model.attendanceTracking!.pScheduledHours) ?? "- - : - -") + ], + ), + ], + ), + ), + Container( + width: double.infinity, + decoration: BoxDecoration(borderRadius: BorderRadius.only(topLeft: Radius.circular(25), topRight: Radius.circular(25)), color: Colors.white), + margin: EdgeInsets.only(top: 187 - 31), + padding: EdgeInsets.only(left: 21, right: 21, top: 24, bottom: 24), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + "Mark".tr().toText12(), + "Attendance".tr().toText24(), + "Select the method to mark the attendance".tr().toText12(color: Color(0xff535353)), + 24.height, + GridView( + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + padding: EdgeInsets.zero, + 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); + }); + } + }); + // Location.getCurrentLocation((LatLng? latlng) { + // print(latlng!.longitude.toString()); + // }); + }), + attendanceMethod("Wifi", "assets/images/wufu.svg", isWifiEnabled, () {}), + ], + ) + ], + ), + ), + // Positioned( + // top: 187 - 21, + // child: Container( + // padding: EdgeInsets.only(left: 31, right: 31, top: 31, bottom: 16), + // decoration: BoxDecoration(borderRadius: BorderRadius.only(topLeft: Radius.circular(25), topRight: Radius.circular(25)), color: Colors.white), + // child: Column( + // children: [ + // Row( + // children: [commonStatusView("Check In", "09:27"), commonStatusView("Check Out", "- - : - -")], + // ), + // 21.height, + // Row( + // children: [commonStatusView("Late In", "00:27"), commonStatusView("Regular", "08:00")], + // ), + // ], + // ), + // ), + // ), + ], + ), + ) + ], + )) + .animatedSwither(); + }, + ), ); } - Widget attendanceMethod(String title, String image, VoidCallback onPress) => Container( - padding: const EdgeInsets.only(left: 10, right: 10, top: 14, bottom: 14), + Widget attendanceMethod(String title, String image, bool isEnabled, VoidCallback onPress) => Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(15), gradient: const LinearGradient(transform: GradientRotation(.64), begin: Alignment.topRight, end: Alignment.bottomLeft, colors: [ @@ -161,9 +252,26 @@ class _TodayAttendanceScreenState extends State { MyColors.gradiantStartColor, ]), ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [Expanded(child: SvgPicture.asset(image)), title.toText17(isBold: true, color: Colors.white)], + clipBehavior: Clip.antiAlias, + child: Stack( + children: [ + Container( + padding: const EdgeInsets.only(left: 10, right: 10, top: 14, bottom: 14), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded(child: SvgPicture.asset(image)), + title.toText17(isBold: true, color: Colors.white), + ], + ), + ), + if (!isEnabled) + Container( + width: double.infinity, + height: double.infinity, + color: Colors.grey.withOpacity(0.7), + ) + ], ), ).onPress(onPress); diff --git a/lib/ui/landing/widget/services_widget.dart b/lib/ui/landing/widget/services_widget.dart index 955915c..ee77693 100644 --- a/lib/ui/landing/widget/services_widget.dart +++ b/lib/ui/landing/widget/services_widget.dart @@ -144,18 +144,19 @@ class ServicesWidget extends StatelessWidget { SizedBox( height: 105 + 26, child: ListView.separated( - shrinkWrap: true, - physics: const BouncingScrollPhysics(), - padding: const EdgeInsets.only(left: 21, right: 21, top: 13, bottom: 13), - scrollDirection: Axis.horizontal, - itemBuilder: (cxt, index) { - return AspectRatio( - aspectRatio: 105 / 105, - child: ServicesMenuShimmer(), - ); - }, - separatorBuilder: (cxt, index) => 9.width, - itemCount: 4), + shrinkWrap: true, + physics: const BouncingScrollPhysics(), + padding: const EdgeInsets.only(left: 21, right: 21, top: 13, bottom: 13), + scrollDirection: Axis.horizontal, + itemBuilder: (cxt, index) { + return AspectRatio( + aspectRatio: 105 / 105, + child: ServicesMenuShimmer(), + ); + }, + separatorBuilder: (cxt, index) => 9.width, + itemCount: 4, + ), ), ], ); diff --git a/lib/ui/login/login_screen.dart b/lib/ui/login/login_screen.dart index cdcdb94..6e2cbb8 100644 --- a/lib/ui/login/login_screen.dart +++ b/lib/ui/login/login_screen.dart @@ -69,13 +69,12 @@ class _LoginScreenState extends State { } String? firebaseToken; - GetMobileLoginInfoListModel? loginInfo; + Future checkFirebaseToken() async { try { Utils.showLoading(context); firebaseToken = await _firebaseMessaging.getToken(); - loginInfo = await LoginApiClient().getMobileLoginInfoNEW(firebaseToken ?? "", Platform.isAndroid ? "android" : "ios"); - loginInfo!.deviceToken = firebaseToken; + GetMobileLoginInfoListModel? loginInfo = await LoginApiClient().getMobileLoginInfoNEW(firebaseToken ?? "", Platform.isAndroid ? "android" : "ios"); if (loginInfo == null) { Utils.hideLoading(context); print("Device token not found"); @@ -113,7 +112,7 @@ class _LoginScreenState extends State { } Utils.hideLoading(context); if (_autoLogin) { - Navigator.pushNamed(context, AppRoutes.verifyLastLogin, arguments: loginInfo); + Navigator.pushNamed(context, AppRoutes.verifyLastLogin); } else { Navigator.pushNamed(context, AppRoutes.verifyLogin, arguments: "$firebaseToken"); } @@ -129,7 +128,7 @@ class _LoginScreenState extends State { @override Widget build(BuildContext context) { username.text = "15153"; - password.text = "Xy12345@"; + password.text = "Abcd@1234"; return Scaffold( body: Column( children: [ diff --git a/lib/widgets/location/Location.dart b/lib/widgets/location/Location.dart new file mode 100644 index 0000000..bd39e2e --- /dev/null +++ b/lib/widgets/location/Location.dart @@ -0,0 +1,249 @@ +import 'dart:async'; +import 'dart:math'; +import 'dart:ui'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:geolocator/geolocator.dart'; +import 'package:google_directions_api/google_directions_api.dart'; +import 'package:google_maps_flutter/google_maps_flutter.dart'; +import 'package:mohem_flutter_app/classes/utils.dart'; +// import 'package:geodesy/geodesy.dart' as geodesy; + +import '../../classes/app_permissions.dart'; +import '../../theme/colors.dart'; + + +//Created By Mr.Zohaib +class Location { + static _Map map = _Map(); + + static havePermission(Function(bool) callback) { + Geolocator.checkPermission().then((value) async { + if (value == LocationPermission.denied) { + value = await Geolocator.requestPermission(); + callback(![LocationPermission.denied, LocationPermission.deniedForever].contains(value)); + } else { + callback(true); + } + }); + } + + static isEnabled(Function(bool) callback) { + Geolocator.isLocationServiceEnabled().then((value) => callback(value)); + } + + static bool _listeningSettingChange = true; + + static listenGPS({bool change = true, Function(bool)? onChange}) async { + _listeningSettingChange = change; + if (change == false) return; + + Future.doWhile(() async { + await Utils.delay(1000); + var enable = await Geolocator.isLocationServiceEnabled(); + onChange!(enable); + return _listeningSettingChange; + }); + } + + static getCurrentLocation(Function(LatLng?) callback) { + done(Position position) { + //AppStorage.sp.saveLocation(position); + + LatLng? myCurrentLocation = LatLng(position.latitude, position.longitude); + callback(myCurrentLocation); + } + + AppPermissions.location((granted) { + + if (granted) + Geolocator.getLastKnownPosition(forceAndroidLocationManager: true).then((value) { + if (value == null) { + Geolocator.getCurrentPosition().then((value) { + done(value); + }); + } else { + done(value); + } + }); + }); + } + + // static LatLng locationAwayFrom( + // {required LatLng loc1, num distanceMeters = 200.0, num bearing = 270.0}) { + // geodesy.LatLng l1 = geodesy.LatLng(loc1.latitude, loc1.longitude); + // geodesy.LatLng destinationPoint = geodesy.Geodesy() + // .destinationPointByDistanceAndBearing(l1, distanceMeters, bearing); + // return LatLng(destinationPoint.latitude, destinationPoint.longitude); + // } + + static Future distanceTo(LatLng destination) async { + var myLoc = await Geolocator.getLastKnownPosition(); + var distance = 0.0; + if (myLoc != null) { + distance = Geolocator.distanceBetween(destination.latitude, destination.longitude, myLoc.latitude, myLoc.longitude); + } + return distance; + } +} + +class _Map { + Marker createMarker( + String id, { + required LatLng coordinates, + BitmapDescriptor? icon, + VoidCallback? onTap, + }) { + final MarkerId markerId = MarkerId(id); + return Marker( + icon: icon ?? BitmapDescriptor.defaultMarker, + markerId: markerId, + position: coordinates, + flat: false, + // infoWindow: InfoWindow(title: id, snippet: '*'), + onTap: onTap, + ); + } + + CameraPosition initialCamera({required Completer mapController, LatLng? position, double zoom = 12}) { + position = position ?? LatLng(24.7249303, 46.5416656); + CameraPosition riyadhEye = CameraPosition( + target: position, + zoom: zoom, + ); + mapController.future.then((controller) { + controller.animateCamera(CameraUpdate.newCameraPosition(riyadhEye)); + }); + return riyadhEye; + } + + CameraPosition moveTo(LatLng location, {double zoom = 12, double direction = 0.0, required Completer mapController, bool? animation}) { + var camera = CameraPosition(target: location, zoom: zoom, bearing: direction); + mapController.future.then((controller) { + animation ?? false ? controller.animateCamera(CameraUpdate.newCameraPosition(camera)) : controller.moveCamera(CameraUpdate.newCameraPosition(camera)); + }); + return camera; + } + + moveCamera(CameraPosition camera, @required Completer mapController, bool animation) { + mapController.future.then((controller) { + animation ? controller.animateCamera(CameraUpdate.newCameraPosition(camera)) : controller.moveCamera(CameraUpdate.newCameraPosition(camera)); + }); + } + + scrollBy({double x = 0, double y = 0, required Completer mapController, bool animation = true}) { + var camera = CameraUpdate.scrollBy(x, y); + mapController.future.then((controller) { + animation ? controller.animateCamera(camera) : controller.moveCamera(camera); + }); + } + + goToCurrentLocation({Completer? mapController, double? direction = 0.0, bool? animation}) { + Location.getCurrentLocation((location) { + moveTo(location!, zoom: 17, mapController: mapController!, animation: animation, direction: direction!); + }); + } + + var routes = Map(); + + setRoutePolylines(LatLng? source, LatLng? destination, Set polylines, Completer mapController, Function(DirectionsRoute?) completion) { + if (source == null || destination == null) { + completion(null); + return; + } + + var origin = '${source.latitude},${source.longitude}'; + var destin = '${destination.latitude},${destination.longitude}'; + var routeId = '$origin->$destination'; + + createPolyline(DirectionsRoute results) { + List polylineCoordinates = results.overviewPath!.map((e) => LatLng(e.latitude, e.longitude)).toList(); + PolylineId id = PolylineId("route"); + Polyline polyline = Polyline( + polylineId: id, + color: accentColor, + width: 5, + jointType: JointType.round, + startCap: Cap.roundCap, + endCap: Cap.roundCap, + points: polylineCoordinates, + ); + + polylines.removeWhere((element) => true); + polylines.add(polyline); + + LatLngBounds bound = getBounds(coordinates: polylineCoordinates); + focusCameraToLatLngBounds(bound: bound, mapController: mapController, padding: 100); + completion(routes[routeId]); + } + + var availableRoute = routes[routeId]; + if (availableRoute == null) { + var request = DirectionsRequest(origin: origin, destination: destin); + DirectionsService().route(request, (response, status) { + if (status == DirectionsStatus.ok && response.routes!.isNotEmpty) { + routes[routeId] = response.routes!.first; + createPolyline(response.routes!.first); + } + }); + } else { + createPolyline(availableRoute); + } + } + + LatLngBounds getBounds({required List coordinates}) { + var lngs = coordinates.map((c) => c.longitude).toList(); + var lats = coordinates.map((c) => c.latitude).toList(); + + double bottomMost = lngs.reduce(min); + double topMost = lngs.reduce(max); + double leftMost = lats.reduce(min); + double rightMost = lats.reduce(max); + + LatLngBounds bounds = LatLngBounds( + northeast: LatLng(rightMost, topMost), + southwest: LatLng(leftMost, bottomMost), + ); + return bounds; + + double? x0, x1, y0, y1; + for (LatLng latLng in coordinates) { + if (x0 == null) { + x0 = x1 = latLng.latitude; + y0 = y1 = latLng.longitude; + } else { + if (latLng.latitude > x1!) x1 = latLng.latitude; + if (latLng.latitude < x0) x0 = latLng.latitude; + if (latLng.longitude > y1!) y1 = latLng.longitude; + if (latLng.longitude < y0!) y0 = latLng.longitude; + } + } + return LatLngBounds(northeast: LatLng(x1!, y1!), southwest: LatLng(x0!, y0!)); + } + + focusCameraToLatLngBounds({LatLngBounds? bound, Completer? mapController, double? padding}) async { + if (bound == null) return; + + CameraUpdate camera = CameraUpdate.newLatLngBounds(bound, padding!); + final GoogleMapController controller = await mapController!.future; + controller.animateCamera(camera); + } + + focusCameraTo2Points({LatLng? point1, LatLng? point2, Completer? mapController, double? padding}) async { + var source = point1; + var destination = point2; + if (source != null && destination != null) { + // 'package:google_maps_flutter_platform_interface/src/types/location.dart': Failed assertion: line 72 pos 16: 'southwest.latitude <= northeast.latitude': is not true. + LatLngBounds bound; + if (source.latitude <= destination.latitude) { + bound = LatLngBounds(southwest: source, northeast: destination); + } else { + bound = LatLngBounds(southwest: destination, northeast: source); + } + + if (bound == null) return; + + focusCameraToLatLngBounds(bound: bound, mapController: mapController, padding: padding); + } + } +} diff --git a/lib/widgets/nfc/nfc_reader_sheet.dart b/lib/widgets/nfc/nfc_reader_sheet.dart new file mode 100644 index 0000000..84397ba --- /dev/null +++ b/lib/widgets/nfc/nfc_reader_sheet.dart @@ -0,0 +1,187 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:nfc_manager/nfc_manager.dart'; +import 'package:nfc_manager/platform_tags.dart'; + +void showNfcReader(BuildContext context, {required Function(String? nfcId) onNcfScan}) { + showModalBottomSheet( + context: context, + enableDrag: false, + isDismissible: false, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.only(topLeft: Radius.circular(12), topRight: Radius.circular(12)), + ), + backgroundColor: Colors.white, + builder: (context) { + return NfcLayout( + onNcfScan: onNcfScan, + ); + }, + ); +} + +class NfcLayout extends StatefulWidget { + Function(String? nfcId) onNcfScan; + + NfcLayout({required this.onNcfScan}); + + @override + _NfcLayoutState createState() => _NfcLayoutState(); +} + +class _NfcLayoutState extends State { + bool _reading = false; + Widget? mainWidget; + String? nfcId; + + @override + void initState() { + super.initState(); + + NfcManager.instance.startSession(onDiscovered: (NfcTag tag) async { + print(tag.data); + var f = MifareUltralight(tag: tag, identifier: tag.data["nfca"]["identifier"], type: 2, maxTransceiveLength: 252, timeout: 22); + final String identifier = f.identifier.map((e) => e.toRadixString(16).padLeft(2, '0')).join(''); + // print(identifier); // => 0428fcf2255e81 + nfcId = identifier; + + setState(() { + _reading = true; + mainWidget = doneNfc(); + }); + + Future.delayed(const Duration(seconds: 1), () { + NfcManager.instance.stopSession(); + Navigator.pop(context); + widget.onNcfScan(nfcId); + }); + }); + } + + @override + Widget build(BuildContext context) { + (mainWidget == null && !_reading) ? mainWidget = scanNfc() : mainWidget = doneNfc(); + return AnimatedSwitcher(duration: Duration(milliseconds: 500), child: mainWidget); + } + + Widget scanNfc() { + return Container( + key: ValueKey(1), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + height: 30, + ), + Text( + "Ready To Scan", + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 24, + ), + ), + SizedBox( + height: 30, + ), + Image.asset( + "assets/icons/nfc/ic_nfc.png", + height: MediaQuery.of(context).size.width / 3, + ), + SizedBox( + height: 30, + ), + Text( + "Approach an NFC Tag", + style: TextStyle( + fontSize: 18, + ), + ), + SizedBox( + height: 30, + ), + ButtonTheme( + minWidth: MediaQuery.of(context).size.width / 1.2, + height: 45.0, + buttonColor: Colors.grey[300], + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6), + ), + child: RaisedButton( + onPressed: () { + NfcManager.instance.stopSession(); + Navigator.pop(context); + }, + elevation: 0, + child: Text("CANCEL"), + ), + ), + SizedBox( + height: 30, + ), + ], + ), + ); + } + + Widget doneNfc() { + return Container( + key: ValueKey(2), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + height: 30, + ), + Text( + "Successfully Scanned", + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 24, + ), + ), + SizedBox( + height: 30, + ), + Image.asset( + "assets/icons/nfc/ic_done.png", + height: MediaQuery.of(context).size.width / 3, + ), + SizedBox( + height: 30, + ), + Text( + "Approach an NFC Tag", + style: TextStyle( + fontSize: 18, + ), + ), + SizedBox( + height: 30, + ), + ButtonTheme( + minWidth: MediaQuery.of(context).size.width / 1.2, + height: 45.0, + buttonColor: Colors.grey[300], + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6), + ), + child: RaisedButton( + // onPressed: () { + // _stream?.cancel(); + // widget.onNcfScan(nfcId); + // Navigator.pop(context); + // }, + onPressed: null, + elevation: 0, + child: Text("DONE"), + ), + ), + SizedBox( + height: 30, + ), + ], + ), + ); + } +} diff --git a/lib/widgets/swipe/nfc_reader_sheet.dart b/lib/widgets/swipe/nfc_reader_sheet.dart new file mode 100644 index 0000000..3dc357d --- /dev/null +++ b/lib/widgets/swipe/nfc_reader_sheet.dart @@ -0,0 +1,194 @@ +// import 'dart:async'; +// +// import 'package:flutter/material.dart'; +// +// +// void showNfcReader(BuildContext context, {Function onNcfScan}) { +// showModalBottomSheet( +// context: context, +// enableDrag: false, +// isDismissible: false, +// shape: RoundedRectangleBorder( +// borderRadius: BorderRadius.only(topLeft: Radius.circular(12), topRight: Radius.circular(12)), +// ), +// backgroundColor: Colors.white, +// builder: (context) { +// return NfcLayout( +// onNcfScan: onNcfScan, +// ); +// }); +// } +// +// class NfcLayout extends StatefulWidget { +// Function onNcfScan; +// +// NfcLayout({this.onNcfScan}); +// +// @override +// _NfcLayoutState createState() => _NfcLayoutState(); +// } +// +// class _NfcLayoutState extends State { +// StreamSubscription _stream; +// bool _reading = false; +// Widget mainWidget; +// String nfcId; +// +// @override +// void initState() { +// super.initState(); +// +// setState(() { +// // _reading = true; +// // Start reading using NFC.readNDEF() +// _stream = NFC.readNDEF(once: false, throwOnUserCancel: false, readerMode: NFCDispatchReaderMode()).listen((NDEFMessage message) { +// setState(() { +// _reading = true; +// mainWidget = doneNfc(); +// }); +// Future.delayed(const Duration(milliseconds: 500), () { +// _stream?.cancel(); +// widget.onNcfScan(nfcId); +// Navigator.pop(context); +// }); +// print("read NDEF id: ${message.id}"); +// print("NFC Record " + message.payload); +// print("NFC Record Lenght " + message.records.length.toString()); +// print("NFC Record " + message.records.first.id); +// print("NFC Record " + message.records.first.payload); +// print("NFC Record " + message.records.first.data); +// print("NFC Record " + message.records.first.type); +// // widget.onNcfScan(message.id); +// nfcId = message.id; +// }, onError: (e) { +// // Check error handling guide below +// }); +// }); +// } +// +// @override +// Widget build(BuildContext context) { +// (mainWidget == null && !_reading) ? mainWidget = scanNfc() : mainWidget = doneNfc(); +// return AnimatedSwitcher(duration: Duration(milliseconds: 500), child: mainWidget); +// } +// +// Widget scanNfc() { +// return Container( +// key: ValueKey(1), +// child: Column( +// mainAxisSize: MainAxisSize.min, +// children: [ +// SizedBox( +// height: 30, +// ), +// Text( +// "Ready To Scan", +// style: TextStyle( +// fontWeight: FontWeight.bold, +// fontSize: 24, +// ), +// ), +// SizedBox( +// height: 30, +// ), +// Image.asset( +// "assets/images/nfc/ic_nfc.png", +// height: MediaQuery.of(context).size.width / 3, +// ), +// SizedBox( +// height: 30, +// ), +// Text( +// "Approach an NFC Tag", +// style: TextStyle( +// fontSize: 18, +// ), +// ), +// SizedBox( +// height: 30, +// ), +// ButtonTheme( +// minWidth: MediaQuery.of(context).size.width / 1.2, +// height: 45.0, +// buttonColor: Colors.grey[300], +// shape: RoundedRectangleBorder( +// borderRadius: BorderRadius.circular(6), +// ), +// child: RaisedButton( +// onPressed: () { +// _stream?.cancel(); +// Navigator.pop(context); +// }, +// elevation: 0, +// child: Text("CANCEL"), +// ), +// ), +// SizedBox( +// height: 30, +// ), +// ], +// ), +// ); +// } +// +// Widget doneNfc() { +// return Container( +// key: ValueKey(2), +// child: Column( +// mainAxisSize: MainAxisSize.min, +// children: [ +// SizedBox( +// height: 30, +// ), +// Text( +// "Successfully Scanned", +// style: TextStyle( +// fontWeight: FontWeight.bold, +// fontSize: 24, +// ), +// ), +// SizedBox( +// height: 30, +// ), +// Image.asset( +// "assets/images/nfc/ic_done.png", +// height: MediaQuery.of(context).size.width / 3, +// ), +// SizedBox( +// height: 30, +// ), +// Text( +// "Approach an NFC Tag", +// style: TextStyle( +// fontSize: 18, +// ), +// ), +// SizedBox( +// height: 30, +// ), +// ButtonTheme( +// minWidth: MediaQuery.of(context).size.width / 1.2, +// height: 45.0, +// buttonColor: Colors.grey[300], +// shape: RoundedRectangleBorder( +// borderRadius: BorderRadius.circular(6), +// ), +// child: RaisedButton( +// // onPressed: () { +// // _stream?.cancel(); +// // widget.onNcfScan(nfcId); +// // Navigator.pop(context); +// // }, +// onPressed: null, +// elevation: 0, +// child: Text("DONE"), +// ), +// ), +// SizedBox( +// height: 30, +// ), +// ], +// ), +// ); +// } +// } diff --git a/pubspec.lock b/pubspec.lock deleted file mode 100644 index 58ce64a..0000000 --- a/pubspec.lock +++ /dev/null @@ -1,514 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - args: - dependency: transitive - description: - name: args - url: "https://pub.dartlang.org" - source: hosted - version: "2.3.0" - async: - dependency: transitive - description: - name: async - url: "https://pub.dartlang.org" - source: hosted - version: "2.8.2" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - characters: - dependency: transitive - description: - name: characters - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - charcode: - dependency: transitive - description: - name: charcode - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.1" - clock: - dependency: transitive - description: - name: clock - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - collection: - dependency: transitive - description: - name: collection - url: "https://pub.dartlang.org" - source: hosted - version: "1.15.0" - crypto: - dependency: transitive - description: - name: crypto - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.1" - cupertino_icons: - dependency: "direct main" - description: - name: cupertino_icons - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.4" - easy_localization: - dependency: "direct main" - description: - name: easy_localization - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.0" - easy_logger: - dependency: transitive - description: - name: easy_logger - url: "https://pub.dartlang.org" - source: hosted - version: "0.0.2" - fake_async: - dependency: transitive - description: - name: fake_async - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - ffi: - dependency: transitive - description: - name: ffi - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.2" - file: - dependency: transitive - description: - name: file - url: "https://pub.dartlang.org" - source: hosted - version: "6.1.2" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_countdown_timer: - dependency: "direct main" - description: - name: flutter_countdown_timer - url: "https://pub.dartlang.org" - source: hosted - version: "4.1.0" - flutter_lints: - dependency: "direct dev" - description: - name: flutter_lints - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.4" - flutter_localizations: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - flutter_plugin_android_lifecycle: - dependency: transitive - description: - name: flutter_plugin_android_lifecycle - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.5" - flutter_svg: - dependency: "direct main" - description: - name: flutter_svg - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - flutter_web_plugins: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - fluttertoast: - dependency: "direct main" - description: - name: fluttertoast - url: "https://pub.dartlang.org" - source: hosted - version: "8.0.8" - http: - dependency: "direct main" - description: - name: http - url: "https://pub.dartlang.org" - source: hosted - version: "0.13.4" - http_parser: - dependency: transitive - description: - name: http_parser - url: "https://pub.dartlang.org" - source: hosted - version: "4.0.0" - injector: - dependency: "direct main" - description: - name: injector - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" - intl: - dependency: transitive - description: - name: intl - url: "https://pub.dartlang.org" - source: hosted - version: "0.17.0" - js: - dependency: transitive - description: - name: js - url: "https://pub.dartlang.org" - source: hosted - version: "0.6.3" - lints: - dependency: transitive - description: - name: lints - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.1" - local_auth: - dependency: "direct main" - description: - name: local_auth - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.9" - logger: - dependency: "direct main" - description: - name: logger - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - matcher: - dependency: transitive - description: - name: matcher - url: "https://pub.dartlang.org" - source: hosted - version: "0.12.11" - meta: - dependency: transitive - description: - name: meta - url: "https://pub.dartlang.org" - source: hosted - version: "1.7.0" - nested: - dependency: transitive - description: - name: nested - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0" - path: - dependency: transitive - description: - name: path - url: "https://pub.dartlang.org" - source: hosted - version: "1.8.0" - path_drawing: - dependency: transitive - description: - name: path_drawing - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0" - path_parsing: - dependency: transitive - description: - name: path_parsing - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0" - path_provider: - dependency: "direct main" - description: - name: path_provider - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.8" - path_provider_android: - dependency: transitive - description: - name: path_provider_android - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.9" - path_provider_ios: - dependency: transitive - description: - name: path_provider_ios - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.7" - path_provider_linux: - dependency: transitive - description: - name: path_provider_linux - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.4" - path_provider_macos: - dependency: transitive - description: - name: path_provider_macos - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.4" - path_provider_platform_interface: - dependency: transitive - description: - name: path_provider_platform_interface - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.1" - path_provider_windows: - dependency: transitive - description: - name: path_provider_windows - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.4" - permission_handler: - dependency: "direct main" - description: - name: permission_handler - url: "https://pub.dartlang.org" - source: hosted - version: "8.3.0" - permission_handler_platform_interface: - dependency: transitive - description: - name: permission_handler_platform_interface - url: "https://pub.dartlang.org" - source: hosted - version: "3.7.0" - petitparser: - dependency: transitive - description: - name: petitparser - url: "https://pub.dartlang.org" - source: hosted - version: "4.4.0" - platform: - dependency: transitive - description: - name: platform - url: "https://pub.dartlang.org" - source: hosted - version: "3.1.0" - plugin_platform_interface: - dependency: transitive - description: - name: plugin_platform_interface - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.2" - process: - dependency: transitive - description: - name: process - url: "https://pub.dartlang.org" - source: hosted - version: "4.2.4" - provider: - dependency: "direct main" - description: - name: provider - url: "https://pub.dartlang.org" - source: hosted - version: "6.0.1" - shared_preferences: - dependency: transitive - description: - name: shared_preferences - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.11" - shared_preferences_android: - dependency: transitive - description: - name: shared_preferences_android - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.9" - shared_preferences_ios: - dependency: transitive - description: - name: shared_preferences_ios - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.8" - shared_preferences_linux: - dependency: transitive - description: - name: shared_preferences_linux - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.3" - shared_preferences_macos: - dependency: transitive - description: - name: shared_preferences_macos - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.2" - shared_preferences_platform_interface: - dependency: transitive - description: - name: shared_preferences_platform_interface - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" - shared_preferences_web: - dependency: transitive - description: - name: shared_preferences_web - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.2" - shared_preferences_windows: - dependency: transitive - description: - name: shared_preferences_windows - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.3" - shimmer: - dependency: "direct main" - description: - name: shimmer - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" - sizer: - dependency: "direct main" - description: - name: sizer - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.15" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.99" - source_span: - dependency: transitive - description: - name: source_span - url: "https://pub.dartlang.org" - source: hosted - version: "1.8.1" - stack_trace: - dependency: transitive - description: - name: stack_trace - url: "https://pub.dartlang.org" - source: hosted - version: "1.10.0" - stream_channel: - dependency: transitive - description: - name: stream_channel - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - string_scanner: - dependency: transitive - description: - name: string_scanner - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - term_glyph: - dependency: transitive - description: - name: term_glyph - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - test_api: - dependency: transitive - description: - name: test_api - url: "https://pub.dartlang.org" - source: hosted - version: "0.4.3" - typed_data: - dependency: transitive - description: - name: typed_data - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.0" - universal_io: - dependency: transitive - description: - name: universal_io - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.4" - vector_math: - dependency: transitive - description: - name: vector_math - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.1" - win32: - dependency: transitive - description: - name: win32 - url: "https://pub.dartlang.org" - source: hosted - version: "2.3.1" - xdg_directories: - dependency: transitive - description: - name: xdg_directories - url: "https://pub.dartlang.org" - source: hosted - version: "0.2.0" - xml: - dependency: transitive - description: - name: xml - url: "https://pub.dartlang.org" - source: hosted - version: "5.3.1" -sdks: - dart: ">=2.14.0 <3.0.0" - flutter: ">=2.5.0" diff --git a/pubspec.yaml b/pubspec.yaml index ca8fe9c..d38cc5a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -18,7 +18,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev version: 1.0.0+1 environment: - sdk: ">=2.12.0 <3.0.0" + sdk: ">=2.16.0 <3.0.0" # Dependencies specify other packages that your package needs in order to work. # To automatically upgrade your package dependencies to the latest versions @@ -39,16 +39,26 @@ dependencies: provider: ^6.0.1 easy_localization: ^3.0.0 http: ^0.13.4 - permission_handler: ^8.3.0 + permission_handler: ^9.2.0 flutter_svg: ^1.0.0 sizer: ^2.0.15 local_auth: ^1.1.9 fluttertoast: ^8.0.8 shared_preferences: ^2.0.12 - firebase_messaging: ^11.2.6 + firebase_messaging: ^11.2.8 shimmer: ^2.0.0 logger: ^1.1.0 flutter_countdown_timer: ^4.1.0 + nfc_manager: ^3.1.1 + uuid: ^3.0.6 + + # maps + google_maps_flutter: ^2.0.2 + google_maps_utils: ^1.4.0+1 + google_directions_api: ^0.9.0 + geolocator: any + # flutter_compass: ^0.6.1 + google_maps_flutter_web: ^0.3.2 dev_dependencies: @@ -84,6 +94,8 @@ flutter: - assets/images/ - assets/images/login/ - assets/images/logos/ + - assets/icons/nfc/ic_nfc.png + - assets/icons/nfc/ic_done.png # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/assets-and-images/#resolution-aware.