NFC Attendance implement

merge-requests/1/merge
devmirza121 4 years ago
parent 681fe7fb38
commit 68729ddbb9

@ -2,6 +2,9 @@
package="com.mohem_flutter_app">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.USE_BIOMETRIC"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.NFC"/>
<application
android:label="Mohemm"
android:icon="@mipmap/ic_launcher">

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

@ -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<GenericResponseModel?> 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<String, dynamic> 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);
}
}

@ -36,6 +36,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;
@ -43,7 +44,6 @@ class AppState {
String? get getUserName => _username;
set setUserPassword(_password) => password = _password;
MemberLoginListModel? _memberLoginList;

@ -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);
});
}
}

@ -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/";
}

@ -46,6 +46,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;

@ -1,4 +1,5 @@
import 'dart:io';
import 'dart:typed_data';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
@ -8,6 +9,9 @@ import 'package:mohem_flutter_app/generated/codegen_loader.g.dart';
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/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';
@ -25,7 +29,7 @@ Future<void> 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(
@ -77,3 +81,140 @@ class MyApp extends StatelessWidget {
);
}
}
// class MyApp extends StatefulWidget {
// @override
// State<StatefulWidget> createState() => MyAppState();
// }
//
// class MyAppState extends State<MyApp> {
// ValueNotifier<dynamic> result = ValueNotifier(null);
//
// @override
// Widget build(BuildContext context) {
// return MaterialApp(
// home: Scaffold(
// appBar: AppBar(title: Text('NfcManager Plugin Example')),
// body: SafeArea(
// child: FutureBuilder<bool>(
// 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<dynamic>(
// 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;
// }
// });
// }
// }

@ -32,7 +32,7 @@ class MemberInformationListModel {
String? fREQUENCY;
String? fREQUENCYMEANING;
int? fROMROWNUM;
String? gRADEID;
int? gRADEID;
String? gRADENAME;
String? hIREDATE;
int? jOBID;

@ -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>? getMenuEntriesList;
//Attendance Tracking API's & Methods
void fetchAttendanceTracking() async {
Future<bool> fetchAttendanceTracking() 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, null);
}
return true;
}
int calculateSeconds(String time) {
@ -63,16 +72,18 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
}
update() {
isAttendanceTrackingLoading = !isAttendanceTrackingLoading;
isWorkListLoading = !isWorkListLoading;
attendanceTracking?.pSwipeIn = "a";
isTimeRemainingInSeconds = calculateSeconds("00:10:30");
endTime = DateTime.now().millisecondsSinceEpoch + Duration(seconds: isTimeRemainingInSeconds).inMilliseconds;
notifyListeners();
fetchAttendanceTracking();
// 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>? 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<menus.length;i++){
// logger.i(jsonEncode(menus[i].menuEntry.prompt));
// for(int j=0;j<menus[i].menuEntiesList.length;j++){

@ -160,12 +160,12 @@ class _DashboardScreenState extends State<DashboardScreen> {
),
LocaleKeys.timeLeftToday.tr().toText12(color: Colors.white),
9.height,
const ClipRRect(
ClipRRect(
borderRadius: BorderRadius.all(
Radius.circular(20),
),
child: LinearProgressIndicator(
value: 0.7,
value: model.progress,
minHeight: 8,
valueColor: const AlwaysStoppedAnimation<Color>(Colors.white),
backgroundColor: const Color(0xff196D73),
@ -184,8 +184,10 @@ class _DashboardScreenState extends State<DashboardScreen> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.checkIn.tr().toText12(color: Colors.white),
(model.isTimeRemainingInSeconds == 0 ? "--:--" : "09:00").toText14(color: Colors.white, isBold: true),
4.height
(model.attendanceTracking!.pSwipeIn == null ? "--:--" : model.attendanceTracking!.pSwipeIn)
.toString()
.toText14(color: Colors.white, isBold: true),
4.height,
],
).paddingOnly(left: 12),
),

@ -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<TodayAttendanceScreen> {
ValueNotifier<dynamic> 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<DashboardProviderModel>(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<TodayAttendanceScreen> {
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: <Widget>[
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<DashboardProviderModel>(
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: <Widget>[
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<TodayAttendanceScreen> {
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);

@ -69,12 +69,12 @@ class _LoginScreenState extends State<LoginScreen> {
}
String? firebaseToken;
GetMobileLoginInfoListModel? loginInfo;
Future<void> checkFirebaseToken() async {
try {
Utils.showLoading(context);
firebaseToken = await _firebaseMessaging.getToken();
loginInfo = await LoginApiClient().getMobileLoginInfoNEW(firebaseToken ?? "", Platform.isAndroid ? "android" : "ios");
GetMobileLoginInfoListModel? 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<LoginScreen> {
}
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");
}
@ -128,7 +128,7 @@ class _LoginScreenState extends State<LoginScreen> {
@override
Widget build(BuildContext context) {
username.text="15153";
password.text="Ab123456@";
password.text="Xy12345@";
return Scaffold(
body: Column(
children: [

@ -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<double> 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<GoogleMapController> 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<GoogleMapController> 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<GoogleMapController> 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<GoogleMapController> mapController, bool animation = true}) {
var camera = CameraUpdate.scrollBy(x, y);
mapController.future.then((controller) {
animation ? controller.animateCamera(camera) : controller.moveCamera(camera);
});
}
goToCurrentLocation({Completer<GoogleMapController>? mapController, double? direction = 0.0, bool? animation}) {
Location.getCurrentLocation((location) {
moveTo(location!, zoom: 17, mapController: mapController!, animation: animation, direction: direction!);
});
}
var routes = Map<String, DirectionsRoute>();
setRoutePolylines(LatLng? source, LatLng? destination, Set<Polyline> polylines, Completer<GoogleMapController> 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<LatLng> 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<LatLng> coordinates}) {
var lngs = coordinates.map<double>((c) => c.longitude).toList();
var lats = coordinates.map<double>((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<GoogleMapController>? 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<GoogleMapController>? 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);
}
}
}

@ -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<NfcLayout> {
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: <Widget>[
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: <Widget>[
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,
),
],
),
);
}
}

@ -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<NfcLayout> {
// StreamSubscription<NDEFMessage> _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: <Widget>[
// 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: <Widget>[
// 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,
// ),
// ],
// ),
// );
// }
// }

@ -49,6 +49,16 @@ dependencies:
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.

Loading…
Cancel
Save