diff --git a/.DS_Store b/.DS_Store index a56fbee1195862794d118c0cdfdfac9cdb71f645..5f8ef10ed912ce8e2ed1ebe07c1e94047a7fed0e 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/FaceRecogAttendance/FaceRecogAttendance.xcworkspace/xcuserdata/Lucas.xcuserdatad/UserInterfaceState.xcuserstate b/FaceRecogAttendance/FaceRecogAttendance.xcworkspace/xcuserdata/Lucas.xcuserdatad/UserInterfaceState.xcuserstate index 0117166c73664a5a5f2a36f0e73fb376b4bb45b9..8942b8a371cc6e8bbe4d7458b0b94004b888ec15 100644 Binary files a/FaceRecogAttendance/FaceRecogAttendance.xcworkspace/xcuserdata/Lucas.xcuserdatad/UserInterfaceState.xcuserstate and b/FaceRecogAttendance/FaceRecogAttendance.xcworkspace/xcuserdata/Lucas.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/FaceRecogAttendance/FaceRecogAttendance/Controller/AttendanceListViewController.swift b/FaceRecogAttendance/FaceRecogAttendance/Controller/AttendanceListViewController.swift index 10af8d59e73be9315fd391888a6c24b552ad73ad..77fed0b169b999b9f6e127aa57ef52a2ef6f6459 100644 --- a/FaceRecogAttendance/FaceRecogAttendance/Controller/AttendanceListViewController.swift +++ b/FaceRecogAttendance/FaceRecogAttendance/Controller/AttendanceListViewController.swift @@ -11,11 +11,10 @@ import RealmSwift class AttendanceListViewController: UITableViewController { -// let realm = try! Realm() - var notificationToken: NotificationToken? var realm : Realm? var attendance : Results<Attendance>? + // set array of attendance to the var var selectedSession : Session? { didSet { loadAttendance() @@ -26,6 +25,7 @@ class AttendanceListViewController: UITableViewController { super.viewDidLoad() } + //MARK: - TableView Datasource method override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return attendance?.count ?? 1 } @@ -40,6 +40,8 @@ class AttendanceListViewController: UITableViewController { return cell } + //MARK: - Data Manipulation Method + // load array of attendance in a session func loadAttendance() { attendance = selectedSession?.attendances.sorted(byKeyPath: "studentName") tableView.reloadData() diff --git a/FaceRecogAttendance/FaceRecogAttendance/Controller/FaceClassificationViewController.swift b/FaceRecogAttendance/FaceRecogAttendance/Controller/FaceClassificationViewController.swift index 56d63178717b04c708da77c5c5da7760c877410d..5e93c2d3b6f7175a5018dda6c7f207a66c1b7763 100644 --- a/FaceRecogAttendance/FaceRecogAttendance/Controller/FaceClassificationViewController.swift +++ b/FaceRecogAttendance/FaceRecogAttendance/Controller/FaceClassificationViewController.swift @@ -14,7 +14,6 @@ import RealmSwift class FaceClassificationViewController: UIViewController, AVCaptureVideoDataOutputSampleBufferDelegate { - var notificationToken: NotificationToken? var realm : Realm? var attendance : Results<Attendance>? var selectedSession : Session? { @@ -22,11 +21,13 @@ class FaceClassificationViewController: UIViewController, AVCaptureVideoDataOutp loadAttendance() } } - var faceDetected: Bool = false - var verification: Bool = false + let captureSession = AVCaptureSession() let cameraManager = CameraManager() - var capturedFaceCount = 0 + + private var capturedFaceCount = 0 + private var faceDetected: Bool = false + private var verification: Bool = false let label: UILabel = { let label = UILabel() @@ -39,15 +40,13 @@ class FaceClassificationViewController: UIViewController, AVCaptureVideoDataOutp return label }() - override func viewDidLoad() { super.viewDidLoad() -// setupTabBar() -// setupCamera() cameraManager.setupCamera(view: view, delegate: self) setupLabel() } + // setup label at the bottom of the screen func setupLabel() { view.addSubview(label) label.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -32).isActive = true @@ -56,10 +55,10 @@ class FaceClassificationViewController: UIViewController, AVCaptureVideoDataOutp label.heightAnchor.constraint(equalToConstant: 80).isActive = true } + // function to capture every image frame func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) { - - verification = false - faceDetected = false + self.verification = false + self.faceDetected = false guard let pixelBuffer: CVPixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return } // initiate the face recognition model guard let model = try? VNCoreMLModel(for: FaceClassifierV3().model) else { @@ -84,18 +83,18 @@ class FaceClassificationViewController: UIViewController, AVCaptureVideoDataOutp alert.addAction(UIAlertAction.init(title: "No", style: .cancel, handler: nil)) self.present(alert, animated: true, completion: nil) -// if self.verification == true { - let name = self.label.text!.components(separatedBy: "-").first! - print(name) - let newAttendance = Attendance(studentID: "test", studentName: name, dateCreated: Date()) - - try! self.realm?.write { - self.selectedSession?.attendances.append(newAttendance) + if self.verification == true { + let name = self.label.text!.components(separatedBy: "-").first! + print(name) + let newAttendance = Attendance(studentID: "test", studentName: name, dateCreated: Date()) + + try! self.realm?.write { + self.selectedSession?.attendances.append(newAttendance) + } + print("attendance created") + self.cameraManager.captureSession.stopRunning() + return } - print("attendance created") - self.cameraManager.captureSession.stopRunning() -// return -// } } } } else { @@ -104,6 +103,7 @@ class FaceClassificationViewController: UIViewController, AVCaptureVideoDataOutp } //MARK: - Facial Recognition Method + // function to classify faces func classifyFace(image: CVPixelBuffer, model: VNCoreMLModel) { let coreMlRequest = VNCoreMLRequest(model: model) {[weak self] request, error in @@ -130,6 +130,7 @@ class FaceClassificationViewController: UIViewController, AVCaptureVideoDataOutp } } + // function to detect faces func detectFace(image: CIImage){ // try to detect face let detectFaceRequest = VNDetectFaceRectanglesRequest { (request, error) in diff --git a/FaceRecogAttendance/FaceRecogAttendance/Controller/FaceTrackerViewController.swift b/FaceRecogAttendance/FaceRecogAttendance/Controller/FaceTrackerViewController.swift index 8ee8349c384dd1385344d4ac20e867e7712abde3..041067c34e65d1f5a2abee4188ab9245e4f816f4 100644 --- a/FaceRecogAttendance/FaceRecogAttendance/Controller/FaceTrackerViewController.swift +++ b/FaceRecogAttendance/FaceRecogAttendance/Controller/FaceTrackerViewController.swift @@ -33,30 +33,8 @@ class FaceTrackerViewController: UIViewController, AVCaptureVideoDataOutputSampl super.viewDidLoad() promptCommand() cameraManager.setupCamera(view: view, delegate: self) -// setupCamera() } -// func setupCamera() { -// let captureSession = AVCaptureSession() -// captureSession.sessionPreset = .high -// -// guard let captureDevice = AVCaptureDevice.default(AVCaptureDevice.DeviceType.builtInWideAngleCamera, for: AVMediaType.video, position: .front) else { preconditionFailure("A Camera is needed to start the AV session") } -// -// //throw error if no camera is found. -// guard let input = try? AVCaptureDeviceInput(device: captureDevice) else { return } -// captureSession.addInput(input) -// -// captureSession.startRunning() -// -// let previewLayer = AVCaptureVideoPreviewLayer(session: captureSession) -// view.layer.addSublayer(previewLayer) -// previewLayer.frame = view.frame -// -// let dataOutput = AVCaptureVideoDataOutput() -// dataOutput.setSampleBufferDelegate(self, queue: DispatchQueue(label: "videoQueue")) -// captureSession.addOutput(dataOutput) -// } - // this function capture the output image frame by frame func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) { guard let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer), @@ -106,7 +84,7 @@ class FaceTrackerViewController: UIViewController, AVCaptureVideoDataOutputSampl } } - //MARK:- Firebase method + //MARK:- Firebase upload method // upload image to firebase storage fileprivate func uploadImages(image: UIImage, completion: @escaping (_ url: String?) -> Void) { // convert UIImage to jpg format diff --git a/FaceRecogAttendance/FaceRecogAttendance/Controller/LoginViewController.swift b/FaceRecogAttendance/FaceRecogAttendance/Controller/LoginViewController.swift index 391d6198b8e3cc46258ff06c12b4dad7c3783186..e0e80a4332dd750e135d8ac6e78e0eac6e263eae 100644 --- a/FaceRecogAttendance/FaceRecogAttendance/Controller/LoginViewController.swift +++ b/FaceRecogAttendance/FaceRecogAttendance/Controller/LoginViewController.swift @@ -16,17 +16,21 @@ class LoginViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() + self.hideKeyboardWhenTappedAround() } + // function to check if admin credentials enter is correct func checkifAdmin(username: String, password: String){ if username == "admin" && password == "admin" { isLogin = true + } else { + isLogin = false } - isLogin = false return } @IBAction func loginButtonPressed(_ sender: UIButton) { + checkifAdmin(username: emailTextField.text!, password: passwordTextField.text!) if isLogin == true { performSegue(withIdentifier: "goToAdmin", sender: self) } else { diff --git a/FaceRecogAttendance/FaceRecogAttendance/Controller/ModuleListViewController.swift b/FaceRecogAttendance/FaceRecogAttendance/Controller/ModuleListViewController.swift index 4d4ff11ef91af314ca7a3acbe1b324e7c3b4046c..705d73188a27315078bb494bbaedceb94198e29f 100644 --- a/FaceRecogAttendance/FaceRecogAttendance/Controller/ModuleListViewController.swift +++ b/FaceRecogAttendance/FaceRecogAttendance/Controller/ModuleListViewController.swift @@ -29,7 +29,7 @@ class ModuleListViewController: UITableViewController { onLogin() } - //MARK - TableView Datasource Method + //MARK: - TableView Datasource Method override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return modules?.count ?? 1 } @@ -63,29 +63,7 @@ class ModuleListViewController: UITableViewController { } } - //MARK - Data Manipulation Methods - // function to present all modules from database -// func loadModules() { -// modules = realm.objects(Module.self) -// tableView.reloadData() -// } - - deinit { - notificationToken?.invalidate() - } - - // function to create a module object in the database -// func saveModule(module: Module) { -// do { -// try realm.write { -// realm.add(module) -// } -// } catch { -// print("Error saving module \(error)") -// } -// } - - //MARK: - Add New Modules + //Add New Modules button @IBAction func addButtonPressed(_ sender: UIBarButtonItem) { var moduleNameTextField = UITextField() @@ -122,6 +100,11 @@ class ModuleListViewController: UITableViewController { present(alert, animated: true, completion: nil) } + //MARK: - Realm Sync Data Manipulation Methods + deinit { + notificationToken?.invalidate() + } + // check if user can access to synced realm func onLogin() { let user = app.currentUser! @@ -138,8 +121,7 @@ class ModuleListViewController: UITableViewController { } } - //MARK: - Data Manipulation Methods - // if realm is accessed, load the database + // If user is able to access realm func onRealmOpened(_ realm: Realm) { modules = realm.objects(Module.self) diff --git a/FaceRecogAttendance/FaceRecogAttendance/Controller/RegisterViewController.swift b/FaceRecogAttendance/FaceRecogAttendance/Controller/RegisterViewController.swift index ad4f6e83339b98d570b76739824d9bf4bea97242..f3070e4969c8312a8f330f645ac943a88e101be1 100644 --- a/FaceRecogAttendance/FaceRecogAttendance/Controller/RegisterViewController.swift +++ b/FaceRecogAttendance/FaceRecogAttendance/Controller/RegisterViewController.swift @@ -26,7 +26,6 @@ class RegisterViewController: UIViewController { signUp() } - @IBAction func recordButtonPressed(_ sender: UIButton) { studentID = studentIDTextField.text! studentName = nameTextField.text! @@ -60,11 +59,13 @@ class RegisterViewController: UIViewController { } } + //MARK: - Realm Sync Data Manipulation Method + // disable notification token if its not in use deinit { notificationToken?.invalidate() } - // a function that allow student to sign up to the application + // a function that allow user to access to Realm Sync SDK @objc func signUp() { app.login(credentials: Credentials.anonymous) { (result) in // Remember to dispatch back to the main thread in completion handlers @@ -75,7 +76,6 @@ class RegisterViewController: UIViewController { print("Login failed: \(error)") case .success(let user): print("Login as \(user) succeeded!") - // Continue below self.signIn() } } @@ -119,12 +119,11 @@ class RegisterViewController: UIViewController { fatalError("\(error)") } } - } } -// CHANGE THIS TO DELEGATE FUNCTION!!! +// Let keyboard dissapear if press else where extension UIViewController { func hideKeyboardWhenTappedAround() { let tap = UITapGestureRecognizer(target: self, action: #selector(UIViewController.dismissKeyboard)) diff --git a/FaceRecogAttendance/FaceRecogAttendance/Controller/SelectModuleViewController.swift b/FaceRecogAttendance/FaceRecogAttendance/Controller/SelectModuleViewController.swift index bd459af1e50049154fe7a0e3c3372d21dcc192a8..a20b2917ae964acc5749d559a9b6a69a5c821fe4 100644 --- a/FaceRecogAttendance/FaceRecogAttendance/Controller/SelectModuleViewController.swift +++ b/FaceRecogAttendance/FaceRecogAttendance/Controller/SelectModuleViewController.swift @@ -11,14 +11,12 @@ import RealmSwift class SelectModuleViewController: UITableViewController { -// let realm = try! Realm() var notificationToken: NotificationToken? var realm : Realm? var modules : Results<Module>? override func viewDidLoad() { super.viewDidLoad() -// loadModules() onLogin() } @@ -42,6 +40,7 @@ class SelectModuleViewController: UITableViewController { performSegue(withIdentifier: "goToSelectSession", sender: self) } + // set variable in the next view controller override func prepare(for segue: UIStoryboardSegue, sender: Any?) { let destinationVC = segue.destination as! SelectSessionViewController @@ -51,19 +50,12 @@ class SelectModuleViewController: UITableViewController { } } - //MARK - Data Manipulation Methods - // function to present all modules from database -// func loadModules() { -// modules = realm.objects(Module.self) -// tableView.reloadData() -// } - //MARK: - REALM SYNC DATA MANIPULATION METHOD - + // disable notification token if its not in use deinit { notificationToken?.invalidate() } - + // check if user can get access to synced realm func onLogin() { let user = app.currentUser! let partitionValue = "user=\(user.id)" @@ -79,6 +71,7 @@ class SelectModuleViewController: UITableViewController { } } + // If user is able to access realm func onRealmOpened(_ realm: Realm) { modules = realm.objects(Module.self) diff --git a/FaceRecogAttendance/FaceRecogAttendance/Controller/SelectSessionViewController.swift b/FaceRecogAttendance/FaceRecogAttendance/Controller/SelectSessionViewController.swift index d5f39acd0765878e1b601fca1f7956f29fd09fbd..9b237b9081458b1d4252fb39c56ca87d62245639 100644 --- a/FaceRecogAttendance/FaceRecogAttendance/Controller/SelectSessionViewController.swift +++ b/FaceRecogAttendance/FaceRecogAttendance/Controller/SelectSessionViewController.swift @@ -11,10 +11,9 @@ import RealmSwift class SelectSessionViewController: UITableViewController { -// let realm = try! Realm() - var notificationToken: NotificationToken? var realm : Realm? var sessions : Results<Session>? + // set array of session to this var var selectedModule : Module? { didSet{ loadSessions() @@ -25,7 +24,7 @@ class SelectSessionViewController: UITableViewController { super.viewDidLoad() } - //MARK - TableView Datasource method + //MARK: - TableView Datasource method override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return sessions?.count ?? 1 } @@ -44,6 +43,7 @@ class SelectSessionViewController: UITableViewController { performSegue(withIdentifier: "goToFaceRecognition", sender: self) } + // set variable in the next view controller override func prepare(for segue: UIStoryboardSegue, sender: Any?) { let destinationVC = segue.destination as! FaceClassificationViewController @@ -53,6 +53,8 @@ class SelectSessionViewController: UITableViewController { } } + //MARK: - Realm Data Manipulation Method + // load array of sessions func loadSessions() { sessions = selectedModule?.sessions.sorted(byKeyPath: "roomNo") tableView.reloadData() diff --git a/FaceRecogAttendance/FaceRecogAttendance/Controller/SessionListViewController.swift b/FaceRecogAttendance/FaceRecogAttendance/Controller/SessionListViewController.swift index 90d185942821abc891cf75ff9603c6ac8e81cd57..aafbb0f4dfa1797be2bce879eeb052583624336e 100644 --- a/FaceRecogAttendance/FaceRecogAttendance/Controller/SessionListViewController.swift +++ b/FaceRecogAttendance/FaceRecogAttendance/Controller/SessionListViewController.swift @@ -11,27 +11,28 @@ import RealmSwift class SessionListViewController: UITableViewController { - var isCheckAttendancePressed: Bool? var notificationToken: NotificationToken? var realm : Realm? var sessions : Results<Session>? + // set array of session to this var var selectedModule : Module? { didSet{ loadSessions() } } + var isCheckAttendancePressed: Bool? override func viewDidLoad() { super.viewDidLoad() } - @IBAction func addButtonPressed(_ sender: UIBarButtonItem) { var sessionRoomNo = UITextField() var sessionDateTextField = UITextField() var sessionTimeTextField = UITextField() + // add a notification let alert = UIAlertController(title: "Add New Session", message: "", preferredStyle: .alert) let action = UIAlertAction(title: "Add Session", style: .default) { (action) in let newSession = Session(roomNo: sessionRoomNo.text!, sessionDate: sessionDateTextField.text!, sessionTime: sessionTimeTextField.text!) @@ -64,7 +65,7 @@ class SessionListViewController: UITableViewController { } - //MARK - TableView Datasource method + //MARK: - TableView Datasource method override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return sessions?.count ?? 1 } @@ -85,6 +86,7 @@ class SessionListViewController: UITableViewController { } } + // set variable in next view controller override func prepare(for segue: UIStoryboardSegue, sender: Any?) { let destinationVC = segue.destination as! AttendanceListViewController if let indexPath = tableView.indexPathForSelectedRow { @@ -94,6 +96,7 @@ class SessionListViewController: UITableViewController { } //MARK: - Data Manipulation Method + // load array of sessions in a module func loadSessions() { sessions = selectedModule?.sessions.sorted(byKeyPath: "roomNo") tableView.reloadData() diff --git a/FaceRecogAttendance/FaceRecogAttendance/Controller/StudentViewController.swift b/FaceRecogAttendance/FaceRecogAttendance/Controller/StudentViewController.swift index 9f63d051aa84318eb6f1b3c0e2b87169f394c4df..a4d77f81b81e95bbf04ef97090446ad3c12db3e5 100644 --- a/FaceRecogAttendance/FaceRecogAttendance/Controller/StudentViewController.swift +++ b/FaceRecogAttendance/FaceRecogAttendance/Controller/StudentViewController.swift @@ -20,11 +20,7 @@ class StudentViewController: UITableViewController { onLogin() } - deinit { - notificationToken?.invalidate() - } - - //MARK - Tableview Datasource Method + //MARK: - Tableview Delegate Method override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return students?.count ?? 1 } @@ -35,7 +31,7 @@ class StudentViewController: UITableViewController { return cell } - //MARK - Tableview Delegate Method + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { // print(studentArray[indexPath.row]) performSegue(withIdentifier: "goToStudentDetail", sender: self) @@ -49,20 +45,11 @@ class StudentViewController: UITableViewController { destinationVC.realm = self.realm } } - -// // function to login to synced realm -// func login() { -// app.login(credentials: Credentials.anonymous) { (result) in -// DispatchQueue.main.async { -// switch result { -// case .failure(let error): -// print("Login Failed: \(error)") -// case .success(let user): -// print("Login as \(user) sucdeeded") -// } -// } -// } -// } + //MARK: - Realm Sync Data Manipulation Methods + // disable notification token if its not in use + deinit { + notificationToken?.invalidate() + } // check if user is allow to access to synced realm func onLogin() { @@ -81,6 +68,7 @@ class StudentViewController: UITableViewController { } } + // If user is able to access realm func onRealmOpened(_ realm: Realm) { students = realm.objects(Student.self) diff --git a/FaceRecogAttendance/FaceRecogAttendance/View/Base.lproj/Main.storyboard b/FaceRecogAttendance/FaceRecogAttendance/View/Base.lproj/Main.storyboard index 24c361d3072aaef88252be7649e2c61840a5254b..cb3a04b09c68866f5b1ea88702eb081186ebdce2 100644 --- a/FaceRecogAttendance/FaceRecogAttendance/View/Base.lproj/Main.storyboard +++ b/FaceRecogAttendance/FaceRecogAttendance/View/Base.lproj/Main.storyboard @@ -397,7 +397,7 @@ <textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Password" textAlignment="center" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="joU-hn-o2f"> <rect key="frame" x="49" y="50" width="317" height="45"/> <fontDescription key="fontDescription" type="system" pointSize="25"/> - <textInputTraits key="textInputTraits"/> + <textInputTraits key="textInputTraits" secureTextEntry="YES"/> </textField> </subviews> <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>