diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..aa724b7
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,15 @@
+*.iml
+.gradle
+/local.properties
+/.idea/caches
+/.idea/libraries
+/.idea/modules.xml
+/.idea/workspace.xml
+/.idea/navEditor.xml
+/.idea/assetWizardSettings.xml
+.DS_Store
+/build
+/captures
+.externalNativeBuild
+.cxx
+local.properties
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..26d3352
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
new file mode 100644
index 0000000..61a9130
--- /dev/null
+++ b/.idea/compiler.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
new file mode 100644
index 0000000..6513874
--- /dev/null
+++ b/.idea/gradle.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml
new file mode 100644
index 0000000..a5f05cd
--- /dev/null
+++ b/.idea/jarRepositories.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..d5d35ec
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/.gitignore b/app/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/app/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
new file mode 100644
index 0000000..336d2a5
--- /dev/null
+++ b/app/build.gradle
@@ -0,0 +1,58 @@
+plugins {
+ id 'com.android.application'
+}
+
+android {
+ compileSdkVersion 30
+ buildToolsVersion "29.0.3"
+
+ defaultConfig {
+ applicationId "com.example.attendancemgr"
+ minSdkVersion 26
+ targetSdkVersion 30
+ versionCode 1
+ versionName "1.0"
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+}
+
+dependencies {
+
+ implementation 'androidx.appcompat:appcompat:1.3.1'
+ implementation 'com.google.android.material:material:1.4.0'
+ implementation 'androidx.constraintlayout:constraintlayout:2.1.0'
+ implementation 'androidx.room:room-runtime:2.3.0'
+ implementation 'androidx.annotation:annotation:1.1.0'
+ implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.3.1'
+ implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1'
+ implementation 'androidx.navigation:navigation-fragment:2.3.5'
+ implementation 'androidx.navigation:navigation-ui:2.3.5'
+ implementation 'androidx.legacy:legacy-support-v4:1.0.0'
+ implementation 'androidx.recyclerview:recyclerview:1.1.0'
+ implementation 'androidx.work:work-rxjava3:2.5.0-rc01'
+ testImplementation 'junit:junit:4.13.2'
+ androidTestImplementation 'androidx.test.ext:junit:1.1.3'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
+ annotationProcessor 'androidx.room:room-compiler:2.3.0'
+
+ // Room components
+ implementation "androidx.room:room-runtime:2.3.0"
+ annotationProcessor "androidx.room:room-compiler:2.3.0"
+
+ // Lifecycle components
+ implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
+ annotationProcessor "androidx.lifecycle:lifecycle-compiler:2.3.1"
+
+}
\ No newline at end of file
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
new file mode 100644
index 0000000..481bb43
--- /dev/null
+++ b/app/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/app/src/androidTest/java/com/example/attendancemgr/ExampleInstrumentedTest.java b/app/src/androidTest/java/com/example/attendancemgr/ExampleInstrumentedTest.java
new file mode 100644
index 0000000..b411db0
--- /dev/null
+++ b/app/src/androidTest/java/com/example/attendancemgr/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package com.example.attendancemgr;
+
+import android.content.Context;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * @see Testing documentation
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ assertEquals("com.example.attendancemgr", appContext.getPackageName());
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..b7796f9
--- /dev/null
+++ b/app/src/main/AndroidManifest.xml
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/example/attendancemgr/MainActivity.java b/app/src/main/java/com/example/attendancemgr/MainActivity.java
new file mode 100644
index 0000000..4705e9a
--- /dev/null
+++ b/app/src/main/java/com/example/attendancemgr/MainActivity.java
@@ -0,0 +1,722 @@
+package com.example.attendancemgr;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.graphics.Color;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.os.AsyncTask;
+import android.os.Build;
+import android.os.Bundle;
+import android.util.Base64;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.ProgressBar;
+import android.widget.Spinner;
+import android.widget.Toast;
+
+import androidx.activity.result.ActivityResult;
+import androidx.activity.result.ActivityResultCallback;
+import androidx.activity.result.ActivityResultLauncher;
+import androidx.activity.result.contract.ActivityResultContracts;
+import androidx.annotation.RequiresApi;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.ViewModelProvider;
+
+import com.example.attendancemgr.ui.CourseListAdapter;
+import com.example.attendancemgr.database.AgentCourse;
+import com.example.attendancemgr.database.AttendanceCourse;
+import com.example.attendancemgr.database.CourseViewModel;
+import com.example.attendancemgr.database.EnrolCourse;
+import com.google.android.material.snackbar.Snackbar;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.Timer;
+import java.util.TimerTask;
+
+public class MainActivity extends AppCompatActivity {
+ private final String[] Courses = {"Select a course","PHY101", "PHY102"};
+ private String chosenCourse, jsonAttendance, jsonEnrol;
+ private final int DOWNLOADING = 1;
+ private final int OPEN_ATTENDANCE_CODE = 2;
+ private final int NOT_DOWNLOADING = 0;
+ private LinkedList lecturerFP;
+ private final String ATTENDANCE_RECORD = "Attendance list";
+ private final String COURSE_CODE = "Course code";
+ private final String ATT_COURSE = "Course";
+ private final String ATT_TUTOR_FP = "Authenticate tutor";
+ private final String ATD_TUTOR_FP = "Tutor FPs";
+ private static final String STUDENT_MATCH = "Authenticate student";
+ private final String ATT_STDs_FPs = "Students FPs";
+ public final String ATT_STDs_NOs = "Students NOs";
+ public final String ATT_STDs_IDs = "Attendance IDs";
+ public final String TUTOR_VALID = "is tutor valid?";
+ private LinkedList AdmNos;
+ private boolean FPStatus, pb_is_Visible, isSubmitted, isSubmitting;
+ private int downloadStatus = NOT_DOWNLOADING;
+ private ProgressBar pb;
+ private LinkedList studentsFP;
+ private LinkedList IDs;
+ Button scanButton, regButton, submitRecordButton;
+ private CourseListAdapter listAdapter;
+ private CourseViewModel mCourseViewModel;
+ private List mAgentCourses;
+ private List attendanceCourses;
+ private List enrolCourses;
+ private List courseString;
+ private final int TUTOR_OK = 234;
+ private final int ATT_OK = 432;
+ private int idOPen = -1, tempID;
+ private AgentCourse openedCourse;
+ public static final String AddressFile = "bt_address_file";
+
+ private ActivityResultCallback attCallback = result -> {
+
+ //Pattern pat;
+ //Matcher mat;
+ if(result.getResultCode() == ATT_OK){ if(result.getData().hasExtra(ATT_STDs_NOs)) {
+ for (String data : result.getData().getExtras().getStringArrayList(ATT_STDs_NOs)) {
+ if (data.length() > 20) {
+ // ga wanda ya fara daukar attendance na farko kafin enrollment
+ /* mCourseViewModel.insert(new AttendanceCourse(chosenCourse,
+ null,
+ Base64.decode(data, Base64.DEFAULT),
+ AttendanceCourse.Sub_Status.unsubmitted,
+ AttendanceCourse.Cap_Status.captured));*/
+ } else {
+ /* pat = Pattern.compile(data);
+ mat = pat.matcher("&");
+ if (mat.find()) {*/
+ String[] admNo_id = data.split("&");
+ // for the enrolled
+ /* mCourseViewModel.update(new AttendanceCourse(Integer.parseInt(admNo_id[0]),
+ chosenCourse,
+ admNo_id[1],
+ null,
+ AttendanceCourse.Sub_Status.unsubmitted,
+ AttendanceCourse.Cap_Status.captured));
+*/
+ /*}else {
+ mCourseViewModel.insert(new AttendanceCourse(chosenCourse, data, null, AttendanceCourse.Sub_Status.unsubmitted, AttendanceCourse.Cap_Status.captured));
+ }*/
+ }
+ }
+ if (openedCourse != null ){
+ openedCourse.setAtt_status(AgentCourse.Att_Status.closed);
+ mCourseViewModel.update(openedCourse);
+ }
+
+ if (result.getData().hasExtra("BTAddress")) saveAddress((String) result.getData().getExtras().get("BTAddress"));
+ }}
+ };
+
+ ActivityResultCallback tutorScanCallback = result -> {
+ if (result.getResultCode() == TUTOR_OK){
+ for (AgentCourse course : mAgentCourses) {
+ if (course.getCourse().equals(chosenCourse)) {
+ course.setAtt_status(AgentCourse.Att_Status.open);
+ openedCourse = course;
+ }
+ break;
+ }
+ getAtt_EnrolData(null);
+ }
+ if (result.getData() != null && result.getData().hasExtra("BTAddress")) saveAddress((String) result.getData().getExtras().get("BTAddress"));
+ };
+ public Spinner courseSpinner;
+ ActivityResultLauncher tutorScanLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), tutorScanCallback);
+ ActivityResultLauncher attLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), attCallback);
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+ //mCourseViewModel = new CourseViewModel(getApplication());
+ mCourseViewModel = new ViewModelProvider(this).get(CourseViewModel.class);
+ courseSpinner = findViewById(R.id.selectCourseSpinner);
+ LiveData> agentLiveData = mCourseViewModel.getAllAgentCourses();
+ LiveData> attLiveData = mCourseViewModel.getAllAttendanceCourses();
+ LiveData> enrolLiveData = mCourseViewModel.getAllEnrolCourses();
+ /*ActionBar bar = this.getActionBar();
+ Toast.makeText(this, bar.getTitle(), Toast.LENGTH_SHORT).show();*/
+ courseString = new LinkedList<>();
+
+ if (openedCourse != null) mCourseViewModel.update(openedCourse);
+
+ ArrayAdapter mAdapter = new ArrayAdapter<>(MainActivity.this, R.layout.spinner_text);
+ mAdapter.setNotifyOnChange(true);
+
+ agentLiveData.observe(MainActivity.this, agentCourses -> {
+ if (agentCourses != null){
+ mAgentCourses = agentCourses;
+ courseString.clear();
+ for (AgentCourse course: agentCourses) {
+ courseString.add(course.getCourse());
+ }
+ mAdapter.clear();
+ mAdapter.insert("Please select a course", 0);
+ mAdapter.addAll(courseString);
+ getAllRecords();
+ }
+ });
+
+ Thread t = new Thread(() -> {
+ if(mCourseViewModel.getAnyCourse().length<1) initAgentCourses();
+ });
+ t.start();
+
+ courseSpinner.setAdapter(mAdapter);
+
+ courseSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView> parent, View view, int position, long id) {
+ chosenCourse = mAdapter.getItem(position);
+ if (!chosenCourse.equals(mAdapter.getItem(0))) {
+ if(idOPen != position && downloadStatus == NOT_DOWNLOADING){
+ if (chosenCourse!=null && isWifiCxd()) {
+ tempID = position;
+ getFP(chosenCourse);
+ } else {
+ Toast.makeText(MainActivity.this, "No Internet connection.", Toast.LENGTH_SHORT).show();
+ }
+ } else {
+ getAtt_EnrolData(position);
+ }
+
+ } else {
+ Toast.makeText(MainActivity.this, "Please select a course.", Toast.LENGTH_LONG).show();
+ }
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView> parent) {
+ chosenCourse = Courses[0];
+ }
+ });
+
+ enrolLiveData.observe(this, enrolCourses1 ->{
+ enrolCourses = enrolCourses1;
+ updateSubmitButton();
+ });
+
+ attLiveData.observe(this, attendanceCourses1 -> {
+ if (attendanceCourses1!=null){
+ attendanceCourses = attendanceCourses1;
+ updateSubmitButton();
+ }
+ });
+
+ pb = findViewById(R.id.progressBarSelectCourse);
+ pb.setVisibility(View.INVISIBLE);
+ FPStatus = false;
+ scanButton = findViewById(R.id.scanFPButton);
+ regButton = findViewById(R.id.registerTutorButton);
+ scanButton.setVisibility(View.INVISIBLE);
+ submitRecordButton = findViewById(R.id.submitRecordButton);
+ regButton.setBackgroundColor(Color.GREEN);
+ //
+ lecturerFP = new LinkedList<>();
+ AdmNos = new LinkedList<>();
+ studentsFP = new LinkedList<>();
+ IDs = new LinkedList<>();
+
+ scanButton.setOnClickListener(view -> {
+ if (!pb_is_Visible && getLecturerFP() != null){
+ scanTutorFP();
+ }
+ });
+
+ regButton.setOnClickListener(view ->{
+ if (!pb_is_Visible) {
+ Intent intent = new Intent(MainActivity.this, RegisterTutor.class);
+ startActivity(intent);
+ }
+ });
+
+ // Update the cached copy of the words in the adapter.
+ //adapter.notifyDataSetChanged();
+
+ submitRecordButton.setOnClickListener(View -> {
+ if (!isSubmitted && !pb_is_Visible && !isSubmitting){
+ submitRecord();
+ }
+ });
+
+ }
+
+ private String[] convertToArray(List agentCourses) {
+ ArrayList courses = new ArrayList<>();
+ for (AgentCourse course : agentCourses) {
+ courses.add(course.getCourse());
+ }
+ return (String[]) courses.toArray();
+ }
+
+ private void scanTutorFP() {
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setPackage("com.fgtit.reader");
+ if (!getAddress().equals("No_Address"))
+ intent.putExtra("bt_Address", getAddress());
+ intent.putExtra(ATT_COURSE, chosenCourse);
+ intent.putExtra(ATT_TUTOR_FP, getLecturerFP().toArray());
+ tutorScanLauncher.launch(intent);
+
+ }
+
+ public LinkedList getLecturerFP() {
+ SharedPreferences preferences = this.getSharedPreferences("Tutors", MODE_PRIVATE);
+ String defaultData = "No_FP";
+ String fpStrings = preferences.getString("tutorsFP", defaultData);
+ if (!fpStrings.equals(defaultData)) {
+ String[] fpStringsArray = fpStrings.split(" ");
+ for (String fp : fpStringsArray) {
+ lecturerFP.add(Base64.decode(fp, Base64.DEFAULT));
+ }
+ }
+ return lecturerFP;
+ }
+ private void initAgentCourses(){
+ final String [] courses = {"PHY101", "PHY401", "PHY102",
+ "PHY302"};
+ for (int i = 0 ; i <= courses.length - 1 ; i++) {
+ AgentCourse course = new AgentCourse("Sciences","Physics", courses[i], AgentCourse.Att_Status.closed, AgentCourse.Sub_Status.unsubmitted);
+ mCourseViewModel.insert(course);
+
+ }
+ }
+ void getAllRecords(){
+ attendanceCourses = mCourseViewModel.getAllAttendanceCourses().getValue();
+ enrolCourses = mCourseViewModel.getAllEnrolCourses().getValue();
+ }
+ void updateSubmitButton(){
+ if (isRecordSubmitted()){
+ submitRecordButton.setBackgroundColor(Color.GREEN);
+ isSubmitted = true;
+ } else {
+ submitRecordButton.setBackgroundColor(Color.RED);
+ isSubmitted = false;
+ }
+ }
+ private boolean isRecordSubmitted() {
+ int count = 0;
+ if (attendanceCourses != null) {
+ for (AttendanceCourse course : attendanceCourses) {
+ if (course.getSub_Status() == AttendanceCourse.Sub_Status.unsubmitted &&
+ course.getCap_status().equals(AttendanceCourse.Cap_Status.captured)) count++;
+ }
+ }
+ if (enrolCourses != null) {
+ for (EnrolCourse course : enrolCourses) {
+ if (course.getSub_status() == EnrolCourse.Sub_Status.unsubmitted) count++;
+ }
+ }
+
+ return count<1;
+ }
+
+ private void getFP(String chosenCourse) {
+ class DownloadFP extends AsyncTask{
+ @Override
+ protected void onPreExecute() {
+ super.onPreExecute();
+ pb.setVisibility(View.VISIBLE);
+ downloadStatus = DOWNLOADING;
+ pb_is_Visible = true;
+ }
+
+ @Override
+ protected void onPostExecute(String data) {
+ super.onPostExecute(data);
+ if (data.equals("timeout")){
+ Toast.makeText(MainActivity.this, "Connection timeout!", Toast.LENGTH_SHORT).show();
+ } else if (!data.isEmpty()){
+ try {
+ storeAttendanceData(data);
+ idOPen = tempID;
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ scanButton.setVisibility(View.VISIBLE);
+ }
+ else {
+ Toast.makeText(MainActivity.this, "Lecturer or course details incomplete!", Toast.LENGTH_SHORT).show();
+
+ }
+ pb.setVisibility(View.INVISIBLE);
+ pb_is_Visible = false;
+ downloadStatus = NOT_DOWNLOADING;
+
+ }
+
+ @Override
+ protected String doInBackground(Void... voids) {
+
+ String login_url = "http://www.gstcbunza2012.org.ng/fas/fetch_data.php";
+ try {
+ java.net.URL url = new URL(login_url);
+ try {
+ HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
+ httpURLConnection.setRequestMethod("POST");
+ httpURLConnection.setReadTimeout(15000);
+ httpURLConnection.setConnectTimeout(15000);
+ httpURLConnection.setDoInput(true);
+ httpURLConnection.setDoOutput(true);
+
+ OutputStream outputStream = httpURLConnection.getOutputStream();
+ BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream, "UTF-8"));
+ String post_data = URLEncoder.encode("course", "UTF-8") + "=" + URLEncoder.encode(chosenCourse, "UTF-8");
+ bufferedWriter.write(post_data);
+ bufferedWriter.flush();
+ bufferedWriter.close();
+
+ InputStream inputStream = httpURLConnection.getInputStream();
+ BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "iso-8859-1"));
+ StringBuilder result = new StringBuilder();
+ String line;
+ new Timer().schedule(new TimerTask() {
+ @RequiresApi(api = Build.VERSION_CODES.O)
+ @Override
+ public void run() {
+ if (inputStream == null){
+ onPostExecute("timeout");
+ httpURLConnection.disconnect();
+
+ }
+ }
+
+ }, 15000);
+ while ((line = bufferedReader.readLine()) != null) {
+ result.append(line);
+ }
+ String rslt = result.toString().trim();
+ if (!rslt.isEmpty() & rslt.length()>20) {
+ return rslt;
+
+ }
+ bufferedReader.close();
+ inputStream.close();
+ httpURLConnection.disconnect();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return "";
+ }
+ }
+ DownloadFP downloadFP = new DownloadFP();
+ if (isWifiCxd()) {
+ downloadFP.execute();
+ } else {
+ Snackbar.make(MainActivity.this, submitRecordButton, "No network connection", Snackbar.LENGTH_LONG);
+ }
+ }
+
+ private void storeAttendanceData(String data) throws JSONException {
+ JSONArray jsonArray = new JSONArray(data);
+ JSONObject tutorFP;
+
+ StringBuilder builder = new StringBuilder();
+ String tutorFPStrings;
+
+ // JSONObject object = jsonArray.getJSONObject(i);
+ JSONArray tutorsArray = jsonArray.getJSONArray(0);
+
+ for (int j=0; j0) return temp;
+ return new String[0][0];
+ }
+ private boolean prepareAttData(){
+
+ int count2 = 0;
+ for (AttendanceCourse course : attendanceCourses) {
+ if (course.getCap_status().equals(AttendanceCourse.Cap_Status.uncaptured)) {
+ studentsFP.add(course.getFP());
+ AdmNos.add(course.getAdmNo());
+ IDs.add(course.getId());
+
+ }
+ }
+ SharedPreferences preferences = this.getSharedPreferences("Tutors", MODE_PRIVATE);
+ String defaultFP = "";
+ String tutorsFP = preferences.getString("tutorsFP", defaultFP);
+ String[] tutorsFPArray = tutorsFP.split(" ");
+ for (String fp : tutorsFPArray) {
+ lecturerFP.add(Base64.decode(fp, Base64.DEFAULT));
+ count2++;
+ }
+
+ return count2>0;
+ }
+ private void getAtt_EnrolData(Integer position) {
+ final AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
+ builder.setMessage("What would you like to do?");
+ //builder.setTitle("Register Entry or Add Fingerprint");
+
+ builder.setPositiveButton("Enrol Student", (dialog, which) -> {
+ if(isSubmitting){
+ Toast.makeText(this, "Please wait, system is busy.", Toast.LENGTH_SHORT).show();
+ } else {
+ String[][] un_enrolled = getAllUn_enrolledAttendees();
+ Intent intent = new Intent(MainActivity.this, enrolActivity.class);
+ if (un_enrolled.length!=0) intent.putExtra("Un_enrolled", un_enrolled);
+ intent.putExtra("chosenCourse", chosenCourse);
+ startActivity(intent);
+ }
+ });
+
+ builder.setNegativeButton("Take attendance", (dialog, which) -> {
+ if (position==null || mAgentCourses.get(position).getAtt_status().equals(AgentCourse.Att_Status.open)) {
+ if (prepareAttData()) {
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setPackage("com.fgtit.reader");
+ if (!getAddress().equals("No_Address"))
+ intent.putExtra("bt_Address", getAddress());
+
+ intent.putExtra(ATT_COURSE, chosenCourse);
+ intent.putExtra(ATD_TUTOR_FP, lecturerFP.toArray());
+ if (studentsFP != null) intent.putExtra(ATT_STDs_FPs, studentsFP.toArray());
+ if (AdmNos != null) intent.putExtra(ATT_STDs_NOs, AdmNos.toArray());
+ if (IDs != null) intent.putExtra(ATT_STDs_IDs, IDs.toArray());
+ intent.putExtra(STUDENT_MATCH, true);
+
+ attLauncher.launch(intent);
+ dialog.cancel();
+ } else {
+ Toast.makeText(this, "An error has occured!", Toast.LENGTH_LONG).show();
+ }
+ } else {
+ Toast.makeText(this, "Attendance is closed for the course.", Toast.LENGTH_SHORT).show();
+ }
+ });
+ AlertDialog dialog = builder.create();
+ dialog.show();
+ }
+ private String getAddress(){
+ SharedPreferences preferences = this.getSharedPreferences(AddressFile, MODE_PRIVATE);
+ String defaultAddress = "No_Address";
+ return preferences.getString("Address", defaultAddress);
+ }
+
+ @RequiresApi(api = Build.VERSION_CODES.R)
+ void updateAgentCourseSub() throws JSONException {
+ Set att_crs = new HashSet<>(attendanceCourses);
+ int attCount = 0;
+ for (AgentCourse agCourse: mAgentCourses) {
+ for (AttendanceCourse course:att_crs) {
+ if (course.getCourse().equals(agCourse.getCourse()) && course.getCap_status().equals(AttendanceCourse.Cap_Status.captured)) {
+ agCourse.setSub_status(AgentCourse.Sub_Status.submitted);
+ mCourseViewModel.update(agCourse);
+ att_crs.remove(course);
+ attCount++;
+ break;
+ }
+ }
+ }
+ Set enrol_crs = new HashSet<>();
+ for (EnrolCourse crs : enrolCourses) {
+ JSONArray crs_arr = new JSONArray(crs.getCourse());
+ for (int i=0; i0) updateSubmitButton();
+ }
+ private JSONArray prepareRecordJsonArray() throws JSONException {
+ JSONArray attArray = new JSONArray();
+ for (AttendanceCourse course:attendanceCourses) {
+ if (attendanceCourses.size() == 0){
+ break;
+ }else if(course.getCap_status().equals(AttendanceCourse.Cap_Status.captured)) {
+ attArray.put(new JSONObject().put("att_course", course.getCourse()).put("AdmNo", course.getAdmNo()));
+ }
+ }
+ for (EnrolCourse course:enrolCourses) {
+ if (enrolCourses.size() == 0){
+ break;
+ }else{
+ attArray.put(new JSONObject().put("enrol_course", new JSONArray(course.getCourse()))
+ .put("AdmNo", course.getAdmNo())
+ .put("fp", Base64.encodeToString(course.getFP(), Base64.DEFAULT))
+ .put("IDImg", Base64.encodeToString(course.getIDImg(), Base64.DEFAULT))
+ );
+ }
+
+ }
+
+ return attArray;
+ }
+ void submitRecord(){
+ class SubmitRecordAsynTask extends AsyncTask{
+ @Override
+ protected void onPreExecute() {
+ super.onPreExecute();
+ pb.setVisibility(View.VISIBLE);
+ isSubmitting = true;
+ }
+
+ @RequiresApi(api = Build.VERSION_CODES.R)
+ @Override
+ protected void onPostExecute(Boolean o) {
+ super.onPostExecute(o);
+ if (o) {
+ try {
+ updateAgentCourseSub();
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ for (AttendanceCourse course : attendanceCourses) {
+ if (course.getCap_status().equals(AttendanceCourse.Cap_Status.captured)) {
+ course.setSub_Status(AttendanceCourse.Sub_Status.submitted);
+ mCourseViewModel.update(course);
+ }
+ }
+ for (EnrolCourse course : enrolCourses) {
+ course.setSub_status(EnrolCourse.Sub_Status.submitted);
+ mCourseViewModel.update(course);
+ }
+ isSubmitting = false;
+ pb.setVisibility(View.GONE);
+ }
+ }
+
+ @Override
+ protected Boolean doInBackground(Void... params) {
+ String urlString = "http://www.gstcbunza2012.org.ng/fas/c_register.php";
+
+ try {
+ URL url = new URL(urlString);
+ try {
+ HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
+ httpURLConnection.setRequestMethod("POST");
+ httpURLConnection.setRequestProperty("Content-type", "application/json");
+ httpURLConnection.setRequestProperty("Connection", "Keep-Alive");
+ httpURLConnection.setReadTimeout(15000);
+ httpURLConnection.setConnectTimeout(15000);
+ httpURLConnection.setDoInput(true);
+ httpURLConnection.setDoOutput(true);
+ httpURLConnection.connect();
+
+
+ OutputStream outputStream = httpURLConnection.getOutputStream();
+ outputStream.write(prepareRecordJsonArray().toString().getBytes(StandardCharsets.UTF_8));
+
+ InputStream inputStream = httpURLConnection.getInputStream();
+ BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "iso-8859-1"));
+ StringBuilder result = new StringBuilder();
+ String line;
+
+ while ((line = bufferedReader.readLine()) != null) {
+ result.append(line);
+ }
+ String rslt = result.toString().trim();
+ if (rslt.equals("Data successfully submitted")) {
+ return true;
+ }
+ bufferedReader.close();
+ inputStream.close();
+ httpURLConnection.disconnect();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return false;
+ }
+ }
+
+ SubmitRecordAsynTask submit = new SubmitRecordAsynTask();
+ submit.execute();
+
+ }
+ public boolean isWifiCxd() {
+ ConnectivityManager connMgr = (ConnectivityManager) this.getSystemService(Context.CONNECTIVITY_SERVICE);
+ final NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
+
+ return networkInfo!=null && networkInfo.isConnected();
+
+ }
+ public void saveAddress(String mAddress) {
+ SharedPreferences sharedPref = getSharedPreferences(AddressFile, Context.MODE_PRIVATE);
+ SharedPreferences.Editor editor = sharedPref.edit();
+ editor.putString("Address", mAddress);
+
+ editor.apply();
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/attendancemgr/MainActivity2.java b/app/src/main/java/com/example/attendancemgr/MainActivity2.java
new file mode 100644
index 0000000..99eb992
--- /dev/null
+++ b/app/src/main/java/com/example/attendancemgr/MainActivity2.java
@@ -0,0 +1,408 @@
+package com.example.attendancemgr;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.graphics.Color;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.util.Base64;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.widget.ImageView;
+import android.widget.Toast;
+
+import androidx.activity.OnBackPressedCallback;
+import androidx.activity.OnBackPressedDispatcher;
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.appcompat.widget.Toolbar;
+import androidx.drawerlayout.widget.DrawerLayout;
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.ViewModelProvider;
+import androidx.navigation.NavController;
+import androidx.navigation.Navigation;
+import androidx.navigation.fragment.NavHostFragment;
+import androidx.navigation.ui.NavigationUI;
+
+import com.example.attendancemgr.database.AgentCourse;
+import com.example.attendancemgr.database.AttendanceCourse;
+import com.example.attendancemgr.database.CourseViewModel;
+import com.example.attendancemgr.database.EnrolCourse;
+import com.google.android.material.navigation.NavigationView;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import static com.example.attendancemgr.ui.login.LoginActivity.ID_FILE;
+import static com.example.attendancemgr.ui.login.LoginActivity.USERNAME;
+
+public class MainActivity2 extends AppCompatActivity {
+ public static final String ATT_COURSE = "Course";
+ public static final String ATT_TUTOR_FP = "Authenticate tutor";
+ public static final String ATD_TUTOR_FP = "Tutor FPs";
+ public static final String STUDENT_MATCH = "Authenticate student";
+ public static final String ATT_STDs_FPs = "Students FPs";
+ public static final String ATT_STDs_NOs = "Students NOs";
+ public static final String ATT_STDs_IDs = "Attendance IDs";
+
+ private DrawerLayout drawer;
+ private Set orgData = new HashSet<>();
+ private List allCourses;
+ private NavigationView navigationView;
+ private CourseViewModel mCourseViewModel;
+ private boolean isSubmitting, Submitted;
+ private ImageView headerImageView;
+ Toolbar toolbar;
+ public static final String AVAILABLE_JOBS = "Available";
+ public static final String COMPLETED_JOBS = "Completed";
+ public static final String JOBS_FILE = "Jobs file";
+ public static final String NO_DATA = "No_Data";
+ private List attendanceCourses;
+ private List enrolCourses;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main2);
+ toolbar = findViewById(R.id.toolbar);
+ setSupportActionBar(toolbar);
+ headerImageView = findViewById(R.id.imageView);
+ drawer = findViewById(R.id.drawer_layout);
+ navigationView = findViewById(R.id.nav_view);
+ mCourseViewModel = new ViewModelProvider(this).get(CourseViewModel.class);
+ LiveData> allCoursesLiveData = mCourseViewModel.getAllAgentCourses();
+ LiveData> attLiveData = mCourseViewModel.getAllAttendanceCourses();
+ LiveData> enrolLiveData = mCourseViewModel.getAllEnrolCourses();
+ NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.nav_host_fragment);
+ NavController navController = navHostFragment.getNavController();
+
+ /*Bundle b = new Bundle();
+ b.putString("name", "isa");
+ navController.setGraph(R.navigation.mobile_navigation, b);*/
+ NavigationUI.setupActionBarWithNavController(this, navController, drawer);
+ NavigationUI.setupWithNavController(navigationView, navController);
+
+
+ Intent loginIntent = getIntent();
+ if (loginIntent.hasExtra("data")){
+ if (loginIntent.getExtras().get("data") != null){
+ Object[] availsObject = (Object[]) loginIntent.getExtras().get("data");
+ for (Object obj:availsObject) {
+ orgData.add((String[]) obj);
+ }
+
+ /*if (availJobs.size()>0){
+ saveData(availJobs, AVAILABLE_JOBS);
+ }*/
+ }
+ }
+
+ enrolLiveData.observe(this, enrolCourses1 ->{
+ enrolCourses = enrolCourses1;
+ updateBarImage();
+ });
+
+ attLiveData.observe(this, attendanceCourses1 -> {
+ if (attendanceCourses1!=null){
+ attendanceCourses = attendanceCourses1;
+ updateBarImage();
+ }
+ });
+
+ allCoursesLiveData.observe(this, agentCourses -> allCourses = agentCourses);
+
+ OnBackPressedDispatcher dispatcher = this.getOnBackPressedDispatcher();
+ dispatcher.addCallback(new OnBackPressedCallback(true) {
+ @Override
+ public void handleOnBackPressed() {
+ if (!Submitted){
+ final AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity2.this);
+ builder.setMessage("Submit record?");
+ builder.setPositiveButton("Yes", (dialog, which) -> {
+ if (isWifiCxd()){
+ submitRecord();
+ dialog.cancel();
+ }
+ }
+ );
+
+ builder.setNegativeButton("No", (dialog, which) -> dialog.cancel());
+
+ AlertDialog dialog = builder.create();
+
+ dialog.show();
+ } else {
+ finish();
+ }
+ }
+ });
+
+ }
+
+ private void updateBarImage() {
+ if (isRecordSubmitted()) {
+ navigationView.getHeaderView(0).setBackgroundColor(getResources().getColor(R.color.myGreen, null));
+ Submitted = true;
+ } else {
+ navigationView.getHeaderView(0).setBackgroundColor(Color.RED);
+ Submitted = false;
+ }
+
+ }
+ private boolean isRecordSubmitted() {
+ int count = 0;
+ if (attendanceCourses != null) {
+ for (AttendanceCourse course : attendanceCourses) {
+ if (course.getSub_Status() == AttendanceCourse.Sub_Status.unsubmitted && course.getCap_status().equals(AttendanceCourse.Cap_Status.captured)) count++;
+ }
+ }
+ if (enrolCourses != null) {
+ for (EnrolCourse course : enrolCourses) {
+ if (course.getSub_status() == EnrolCourse.Sub_Status.unsubmitted) count++;
+ }
+ }
+
+ return count<1;
+ }
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ // Inflate the menu; this adds items to the action bar if it is present.
+ getMenuInflater().inflate(R.menu.main_activity2, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(@NonNull MenuItem item) {
+ if (item.getTitle() != null){
+ switch (item.getTitle().toString()){
+ case "Submit Record":
+ if (!isWifiCxd()){
+ Toast.makeText(this, R.string.no_network, Toast.LENGTH_SHORT).show();
+ } else if (!isSubmitting){
+ submitRecord();
+ }
+ break;
+ case "Register Tutor":
+ if (!isSubmitting) {
+ Intent i = new Intent(this, RegisterTutor.class);
+ startActivity(i);
+ }
+ break;
+ case "Logout":
+ onBackPressed();
+ break;
+ }
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public boolean onSupportNavigateUp() {
+ NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
+ return NavigationUI.navigateUp(navController, drawer)
+ || super.onSupportNavigateUp();
+ }
+
+ public void saveData(Set data, String Name) {
+ SharedPreferences sharedPref = getSharedPreferences(JOBS_FILE, Context.MODE_PRIVATE);
+ SharedPreferences.Editor editor = sharedPref.edit();
+ editor.putStringSet(Name, data);
+ editor.apply();
+ }
+
+ private String getData(String Name){
+ SharedPreferences preferences = this.getSharedPreferences(JOBS_FILE, MODE_PRIVATE);
+ return preferences.getString(Name, NO_DATA);
+ }
+ public boolean isWifiCxd() {
+ ConnectivityManager connMgr = (ConnectivityManager) this.getSystemService(Context.CONNECTIVITY_SERVICE);
+ final NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
+
+ return networkInfo!=null && networkInfo.isConnected();
+
+ }
+ void updateAgentCourseSub() throws JSONException {
+ Set att_crs = new HashSet<>(attendanceCourses);
+ int attCount = 0;
+ for (AgentCourse agCourse: allCourses) {
+ for (AttendanceCourse course:att_crs) {
+ if (course.getCourse().equals(agCourse.getCourse()) && course.getCap_status().equals(AttendanceCourse.Cap_Status.captured)) {
+ agCourse.setSub_status(AgentCourse.Sub_Status.submitted);
+ mCourseViewModel.update(agCourse);
+ att_crs.remove(course);
+ attCount++;
+ break;
+ }
+ }
+ }
+ Set enrol_crs = new HashSet<>();
+ for (EnrolCourse crs : enrolCourses) {
+ JSONArray crs_arr = new JSONArray(crs.getCourse());
+ for (int i=0; i0) updateBarImage();
+ }
+ private JSONArray prepareRecordJsonArray() throws JSONException {
+ JSONArray attArray = new JSONArray();
+ for (AttendanceCourse course:attendanceCourses) {
+ if (attendanceCourses.size() == 0){
+ break;
+ }else if(course.getCap_status().equals(AttendanceCourse.Cap_Status.captured)) {
+
+ attArray.put(new JSONObject().put("att_course", course.getCourse())
+ .put("AdmNo", course.getAdmNo())
+ .put("date", course.getDate()).put("period", course.getPeriod()));
+ }
+ }
+ for (EnrolCourse course:enrolCourses) {
+ if (enrolCourses.size() == 0){
+ break;
+ }else{
+ if (course.getFP() != null){
+ // for new courses
+ attArray.put(new JSONObject().put("enrol_course", new JSONArray(course.getCourse()))
+ .put("AdmNo", course.getAdmNo())
+ .put("fp", Base64.encodeToString(course.getFP(), Base64.DEFAULT))
+ .put("IDImg", Base64.encodeToString(course.getIDImg(), Base64.DEFAULT))
+ );
+ } else {
+ //for added courses
+ attArray.put(new JSONObject().put("enrol_course", new JSONArray(course.getCourse()))
+ .put("AdmNo", course.getAdmNo()));
+ }
+
+ }
+
+ }
+ attArray.put(new JSONObject().put("uname", getUsername()));
+ attArray.put(new JSONObject().put("code", getCode()));
+ return attArray;
+ }
+
+ private String getCode() {
+ SharedPreferences preferences = this.getSharedPreferences("code file", MODE_PRIVATE);
+ return preferences.getString("code", NO_DATA);
+ }
+
+ private String getUsername(){
+ SharedPreferences preferences = this.getSharedPreferences(ID_FILE, MODE_PRIVATE);
+ return preferences.getString(USERNAME, NO_DATA);
+ }
+ void submitRecord(){
+ class SubmitRecordAsynTask extends AsyncTask {
+ @Override
+ protected void onPreExecute() {
+ super.onPreExecute();
+ toolbar.setSubtitle("Loading...");
+ isSubmitting = true;
+ }
+
+ @Override
+ protected void onPostExecute(Boolean o) {
+ super.onPostExecute(o);
+ if (o) {
+ try {
+ updateAgentCourseSub();
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ for (AttendanceCourse course : attendanceCourses) {
+ if (course.getCap_status().equals(AttendanceCourse.Cap_Status.captured)) {
+ course.setSub_Status(AttendanceCourse.Sub_Status.submitted);
+ mCourseViewModel.update(course);
+ }
+ }
+ for (EnrolCourse course : enrolCourses) {
+ course.setSub_status(EnrolCourse.Sub_Status.submitted);
+ mCourseViewModel.update(course);
+ }
+
+ } else {
+ Toast.makeText(MainActivity2.this, "Error occurred, try again later.", Toast.LENGTH_SHORT).show();
+ }
+ isSubmitting = false;
+ toolbar.setSubtitle("");
+ }
+
+ @Override
+ protected Boolean doInBackground(Void... params) {
+ String urlString = "http://www.gstcbunza2012.org.ng/fas/c_register.php";
+
+ try {
+ URL url = new URL(urlString);
+ try {
+ HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
+ httpURLConnection.setRequestMethod("POST");
+ httpURLConnection.setRequestProperty("Content-type", "application/json");
+ httpURLConnection.setRequestProperty("Connection", "Keep-Alive");
+ httpURLConnection.setReadTimeout(15000);
+ httpURLConnection.setConnectTimeout(15000);
+ httpURLConnection.setDoInput(true);
+ httpURLConnection.setDoOutput(true);
+ httpURLConnection.connect();
+
+
+ OutputStream outputStream = httpURLConnection.getOutputStream();
+ outputStream.write(prepareRecordJsonArray().toString().getBytes(StandardCharsets.UTF_8));
+
+ InputStream inputStream = httpURLConnection.getInputStream();
+ BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "iso-8859-1"));
+ StringBuilder result = new StringBuilder();
+ String line;
+
+ while ((line = bufferedReader.readLine()) != null) {
+ result.append(line);
+ }
+ String rslt = result.toString().trim();
+ if (rslt.equals("Data successfully submitted")) {
+ return true;
+ }
+ bufferedReader.close();
+ inputStream.close();
+ httpURLConnection.disconnect();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return false;
+ }
+ }
+
+ SubmitRecordAsynTask submit = new SubmitRecordAsynTask();
+ submit.execute();
+
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/attendancemgr/RegisterTutor.java b/app/src/main/java/com/example/attendancemgr/RegisterTutor.java
new file mode 100644
index 0000000..ce61250
--- /dev/null
+++ b/app/src/main/java/com/example/attendancemgr/RegisterTutor.java
@@ -0,0 +1,487 @@
+package com.example.attendancemgr;
+
+import androidx.activity.result.ActivityResult;
+import androidx.activity.result.ActivityResultCallback;
+import androidx.activity.result.ActivityResultLauncher;
+import androidx.activity.result.contract.ActivityResultContracts;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.ViewModelProvider;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.graphics.Color;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.util.Base64;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.example.attendancemgr.database.AgentCourse;
+import com.example.attendancemgr.database.CourseViewModel;
+
+import org.json.JSONObject;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class RegisterTutor extends AppCompatActivity {
+androidx.appcompat.widget.AppCompatSpinner coursesSpinner, facultiesSpinner, deptsSpinner;
+private List tutorCourses;
+private EditText OTPText;
+private final ActivityResultCallback tutorScanCallback = result -> {
+ if (result.getResultCode() == RESULT_OK) {
+ storeCourseTutor(result.getData().getByteArrayExtra("tutorBytes"), tutorCourses);
+ OTPText.setText("");
+ }
+
+ assert result.getData() != null;
+ if (result.getData().hasExtra("BTAddress")) saveAddress((String) result.getData().getExtras().get("BTAddress"));
+
+};
+private boolean isVisible;
+private String chosenCourse = "", trueOTP;
+private final String PHONE = "phone number";
+private final String OTP = "otp";
+private List allCourses;
+private String authStage, phoneNumber;
+private Map>> facsMap;
+private Map> selectedFacultyMap;
+private ArrayList selectedDeptCourses;
+TextView coursesView, statusView;
+private ArrayAdapter facSpinnerAdapter;
+private ArrayAdapter deptSpinnerAdapter;
+ProgressBar pb;
+Button scanButton;
+private ActivityResultLauncher enrolTutorLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), tutorScanCallback);
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_register_tutor);
+ coursesSpinner = findViewById(R.id.availableCoursesSpinner);
+ facultiesSpinner = findViewById(R.id.facultySpinner);
+ deptsSpinner = findViewById(R.id.deptSpinner);
+ coursesView = findViewById(R.id.selectedCourses);
+ scanButton = findViewById(R.id.scanFingerButton);
+ OTPText = findViewById(R.id.OTPEditText);
+ pb = findViewById(R.id.progressBar);
+ statusView = findViewById(R.id.statusTextView);
+ CourseViewModel mCourseViewModel = new ViewModelProvider(this).get(CourseViewModel.class);
+
+ LiveData> allCoursesLiveData = mCourseViewModel.getAllAgentCourses();
+ scanButton.setText("next");
+ tutorCourses = new LinkedList<>();
+ pb.setVisibility(View.INVISIBLE);
+
+ facsMap = new HashMap<>();
+
+ allCoursesLiveData.observe(this, agentCourses -> {
+ allCourses = agentCourses;
+ initMaps();
+ });
+
+
+ facSpinnerAdapter = new ArrayAdapter<>(RegisterTutor.this, R.layout.faculty_spinner_text);
+ deptSpinnerAdapter = new ArrayAdapter<>(RegisterTutor.this, R.layout.dept_spinner_text);
+ ArrayAdapter adapter = new ArrayAdapter<>(RegisterTutor.this, R.layout.spinner_text);
+
+ facSpinnerAdapter.insert("Select faculty", 0);
+ facultiesSpinner.setAdapter(facSpinnerAdapter);
+ deptSpinnerAdapter.add("Select department");
+ deptsSpinner.setAdapter(deptSpinnerAdapter);
+ deptSpinnerAdapter.setNotifyOnChange(true);
+
+ adapter.add("Select course");
+ coursesSpinner.setAdapter(adapter);
+ adapter.setNotifyOnChange(true);
+
+ facultiesSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView> adapterView, View view, int i, long l) {
+ if (i>0){
+ if (facsMap.containsKey((String) facultiesSpinner.getAdapter().getItem(i))){
+ selectedFacultyMap = facsMap.get((String) facultiesSpinner.getAdapter().getItem(i));
+
+ Set deptsSet = selectedFacultyMap.keySet();
+ deptSpinnerAdapter.clear();
+ deptSpinnerAdapter.add("Select Department");
+ deptSpinnerAdapter.addAll(deptsSet);
+ deptSpinnerAdapter.notifyDataSetChanged();
+
+ }
+
+ }
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView> adapterView) {
+
+ }
+ });
+ deptsSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView> adapterView, View view, int i, long l) {
+ if(i>0){
+ if (selectedFacultyMap.containsKey(deptSpinnerAdapter.getItem(i))) {
+ selectedDeptCourses = selectedFacultyMap.get(deptSpinnerAdapter.getItem(i));
+ adapter.clear();
+ adapter.add("Select Course");
+ adapter.addAll(selectedDeptCourses);
+ adapter.notifyDataSetChanged();
+ }
+ }
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView> adapterView) {
+
+ }
+ });
+ coursesSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView> parent, View view, int position, long id) {
+ if (position>0) {
+ chosenCourse = selectedDeptCourses.get(position-1);
+ String space = " " + chosenCourse;
+ String viewText = coursesView.getText().toString();
+ if (!viewText.isEmpty() && !viewText.contains(chosenCourse)) {
+ String concat = viewText + " - " + chosenCourse;
+ coursesView.setText(concat);
+ tutorCourses.add(chosenCourse);
+ } else if (viewText.isEmpty()) {
+ coursesView.setText(space);
+ tutorCourses.add(chosenCourse);
+ } else if (viewText.contains(chosenCourse)) {
+ Toast.makeText(RegisterTutor.this, "Course has already been selected", Toast.LENGTH_LONG).show();
+ }
+ scanButton.setText("next");
+ }
+ }
+ @Override
+ public void onNothingSelected(AdapterView> parent) {
+ }
+ });
+
+ allCoursesLiveData.observe(this, agentCourses -> {
+ allCourses = agentCourses;
+ initMaps();
+ ArrayList facs = new ArrayList<>();
+ for (Object obj : facsMap.keySet()) {
+ facs.add( obj.toString());
+ }
+ facSpinnerAdapter.addAll(facs);
+ facSpinnerAdapter.notifyDataSetChanged();
+ });
+ coursesView.setOnLongClickListener(view -> {
+ coursesView.setText("");
+ return true;
+ });
+ OTPText.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
+
+ }
+
+ @Override
+ public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
+ if (authStage.equals(PHONE)) {
+
+
+ if (charSequence.length() == 11) {
+ authStage =
+ phoneNumber = charSequence.toString();
+ OTPText.setText("");
+ authStage = OTP;
+ scanButton.setText("get PIN");
+ getOTP(chosenCourse, phoneNumber);
+
+ }
+ } else {
+ if(charSequence.length() == 6){
+ if (trueOTP.contentEquals(charSequence.toString())){
+ scanButton.setText("Scan");
+ scanTutor(scanButton);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void afterTextChanged(Editable editable) {
+ }
+ });
+ }
+
+ private void initMaps() {
+ Set facSet = new HashSet<>();
+ Set depSet = new HashSet<>();
+ for (AgentCourse course : allCourses) {
+ facSet.add(course.getFaculty());
+ depSet.add(course.getDept());
+ }
+ Map>> facMap = new HashMap<>();
+
+ for (String fac : facSet) {
+ Map> deptMap = new HashMap<>();
+ for (String dep : depSet) {
+ ArrayList deptCourses = new ArrayList<>();
+ for (AgentCourse course : allCourses) {
+ if (dep.equals(course.getDept()) && fac.equals(course.getFaculty())){
+ deptCourses.add(course.getCourse());
+ }
+ }
+
+ if (deptCourses.size()>0) deptMap.put(dep, deptCourses);
+ }
+ facMap.put(fac, deptMap);
+ }
+
+ facsMap = facMap;
+ }
+
+ public void scanTutor(View v) {
+ if (isWifiCxd()) {
+ if (coursesView.getText().toString().isEmpty()) {
+ Toast.makeText(this, "Please select a course", Toast.LENGTH_SHORT).show();
+ } else {
+ if (scanButton.getText().equals("Scan") && !isVisible) {
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setPackage("com.fgtit.reader");
+ /* if(intent.resolveActivity(RegisterTutor.this.getPackageManager())!=null) {
+ }*/
+ intent.putExtra("Enrol tutor", true);
+ if (!getAddress().equals("No_Address"))
+ intent.putExtra("bt_Address", getAddress());
+
+ enrolTutorLauncher.launch(intent);
+ } else if (scanButton.getText().equals("next") && !isVisible && !chosenCourse.equals("")){
+ OTPText.setVisibility(View.VISIBLE);
+ OTPText.setHint("0XXX - XXX - XXXX");
+ statusView.setVisibility(View.VISIBLE);
+ statusView.setText("Please input phone number");
+ authStage = PHONE;
+ }
+ }
+ } else {
+ Toast.makeText(this, "Please connect to the network.", Toast.LENGTH_SHORT).show();
+ }
+ }
+ private void getOTP(String... courses){
+ class getOTPAsynctask extends AsyncTask {
+ @Override
+ protected void onPreExecute() {
+ super.onPreExecute();
+ statusView.setText("Loading...");
+ scanButton.setEnabled(false);
+ isVisible = true;
+ }
+
+ @Override
+ protected void onPostExecute(String otp) {
+ super.onPostExecute(otp);
+ if (otp!=null) trueOTP = otp;
+ OTPText.setVisibility(View.VISIBLE);
+ OTPText.setHint("XXXXXX");
+ statusView.setText("Please input PIN code");
+ scanButton.setEnabled(true);
+ isVisible = false;
+ }
+
+
+ @Override
+ protected String doInBackground(String... strings) {
+ String login_url = "http://www.gstcbunza2012.org.ng/fas/otp_data.php";
+
+ try {
+ java.net.URL url = new URL(login_url);
+ try {
+ HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
+ httpURLConnection.setRequestMethod("POST");
+ httpURLConnection.setReadTimeout(15000);
+ httpURLConnection.setConnectTimeout(15000);
+ httpURLConnection.setDoInput(true);
+ httpURLConnection.setDoOutput(true);
+
+ OutputStream outputStream = httpURLConnection.getOutputStream();
+ BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream, "UTF-8"));
+ String post_data = URLEncoder.encode("course", "UTF-8") + "=" + URLEncoder.encode(strings[0], "UTF-8") + "&" +
+ URLEncoder.encode("phone", "UTF-8") + "=" + URLEncoder.encode(strings[1], "UTF-8");
+ bufferedWriter.write(post_data);
+ bufferedWriter.flush();
+ bufferedWriter.close();
+
+ InputStream inputStream = httpURLConnection.getInputStream();
+ BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "iso-8859-1"));
+ StringBuilder result = new StringBuilder();
+ String line;
+
+ while ((line = bufferedReader.readLine()) != null) {
+ result.append(line);
+ }
+ String rslt = result.toString().trim();
+
+ if (rslt.length()==6) {
+ return rslt;
+
+ }
+ bufferedReader.close();
+ inputStream.close();
+ httpURLConnection.disconnect();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+ }
+ getOTPAsynctask getOTPAsynctask = new getOTPAsynctask();
+ getOTPAsynctask.execute(courses);
+ }
+ private void storeCourseTutor(byte[] result, List tutorCourses) {
+
+ StringBuilder Courses = new StringBuilder();
+ for (int i=0; i {
+ @Override
+ protected void onPreExecute() {
+ super.onPreExecute();
+ pb.setVisibility(View.VISIBLE);
+ isVisible = true;
+ }
+
+ @Override
+ protected void onPostExecute(Boolean saved) {
+ super.onPostExecute(saved);
+ if (saved){
+ Toast.makeText(RegisterTutor.this, "fine!", Toast.LENGTH_SHORT).show();
+ statusView.setTextColor(Color.GREEN);
+ statusView.setText("Data uploaded successfully!");
+ for (String course : tutorCourses) {
+ SharedPreferences sharedPref = getSharedPreferences(course, Context.MODE_PRIVATE);
+ SharedPreferences.Editor editor = sharedPref.edit();
+ editor.putString("tutorFP", Base64.encodeToString(result, Base64.DEFAULT));
+ editor.apply();
+ }
+ } else {
+ statusView.setTextColor(Color.RED);
+ statusView.setText("Data upload failed!");
+ }
+ pb.setVisibility(View.INVISIBLE);
+ isVisible = false;
+ }
+
+
+ @Override
+ protected Boolean doInBackground(String... strings) {
+ String login_url = "http://www.gstcbunza2012.org.ng/fas/tutor.php";
+
+ try {
+ java.net.URL url = new URL(login_url);
+ try {
+ HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
+ httpURLConnection.setRequestMethod("POST");
+ httpURLConnection.setRequestProperty("Content-type", "application/json");
+ httpURLConnection.setRequestProperty("Connection", "Keep-Alive");
+ httpURLConnection.setReadTimeout(15000);
+ httpURLConnection.setConnectTimeout(15000);
+ httpURLConnection.setDoInput(true);
+ httpURLConnection.setDoOutput(true);
+ httpURLConnection.connect();
+
+ JSONObject obj = new JSONObject();
+ obj.put("phone", strings[0]);
+ obj.put("Fingerprint", strings[1]);
+ obj.put("courses", strings[2]);
+
+ OutputStream outputStream = httpURLConnection.getOutputStream();
+
+ outputStream.write(obj.toString().getBytes(StandardCharsets.UTF_8));
+
+ InputStream inputStream = httpURLConnection.getInputStream();
+ BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "iso-8859-1"));
+ StringBuilder result = new StringBuilder();
+ String line;
+
+ while ((line = bufferedReader.readLine()) != null) {
+ result.append(line);
+ }
+ String rslt = result.toString().trim();
+ if (rslt.equals("fine")) {
+ return true;
+
+ }
+ bufferedReader.close();
+ inputStream.close();
+ httpURLConnection.disconnect();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return false;
+ }
+ }
+ UploadFP uploadFP = new UploadFP();
+ uploadFP.execute(data);
+ }
+
+ public boolean isWifiCxd() {
+ ConnectivityManager connMgr = (ConnectivityManager) this.getSystemService(Context.CONNECTIVITY_SERVICE);
+ final NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
+
+ return networkInfo!=null && networkInfo.isConnected();
+
+ }
+
+ public void saveAddress(String mAddress) {
+ SharedPreferences sharedPref = getSharedPreferences(MainActivity.AddressFile, Context.MODE_PRIVATE);
+ SharedPreferences.Editor editor = sharedPref.edit();
+ editor.putString("Address", mAddress);
+ editor.apply();
+ }
+ private String getAddress(){
+ SharedPreferences preferences = this.getSharedPreferences(MainActivity.AddressFile, MODE_PRIVATE);
+ String defaultAddress = "No_Address";
+ return preferences.getString("Address", defaultAddress);
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/attendancemgr/ScanTutor.java b/app/src/main/java/com/example/attendancemgr/ScanTutor.java
new file mode 100644
index 0000000..57cb9c2
--- /dev/null
+++ b/app/src/main/java/com/example/attendancemgr/ScanTutor.java
@@ -0,0 +1,93 @@
+package com.example.attendancemgr;
+
+import androidx.activity.OnBackPressedCallback;
+import androidx.activity.OnBackPressedDispatcher;
+import androidx.appcompat.app.AppCompatActivity;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.View;
+import android.widget.EditText;
+import android.widget.TextView;
+
+import static com.example.attendancemgr.ui.Courses.CoursesFragment.TUTOR_OK;
+
+public class ScanTutor extends AppCompatActivity {
+TextView infoView;
+EditText passcodeText, periodNumberText;
+String passcode;
+int period;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_scan_tutor);
+ infoView = findViewById(R.id.infoView);
+ passcodeText = findViewById(R.id.textPasscode);
+ periodNumberText = findViewById(R.id.textPeriodNumber);
+ periodNumberText.setVisibility(View.GONE);
+
+ Intent intent = getIntent();
+ if (intent.hasExtra("passcode")){
+ passcode = intent.getExtras().getString("passcode");
+ }
+
+ passcodeText.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
+
+ }
+
+ @Override
+ public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
+ if (charSequence.length()==6){
+ if (passcode.equals(charSequence.toString())){
+ periodNumberText.setVisibility(View.VISIBLE);
+ passcodeText.setVisibility(View.INVISIBLE);
+ infoView.setText("Please input period");
+ }
+ }
+ }
+
+ @Override
+ public void afterTextChanged(Editable editable) {
+
+ }
+ });
+
+ periodNumberText.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
+
+ }
+
+ @Override
+ public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
+ if (charSequence.length()>0){
+ period = Integer.parseInt((String) charSequence);
+ Intent intent1 = new Intent();
+ intent1.putExtra("period", period);
+ setResult(TUTOR_OK, intent1);
+ finish();
+ }
+ }
+
+ @Override
+ public void afterTextChanged(Editable editable) {
+
+ }
+ });
+
+ OnBackPressedDispatcher dispatcher = new OnBackPressedDispatcher();
+ dispatcher.addCallback(new OnBackPressedCallback(true) {
+ @Override
+ public void handleOnBackPressed() {
+ setResult(Activity.RESULT_CANCELED);
+ finish();
+ }
+ });
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/attendancemgr/data/LoginDataSource.java b/app/src/main/java/com/example/attendancemgr/data/LoginDataSource.java
new file mode 100644
index 0000000..7b0388e
--- /dev/null
+++ b/app/src/main/java/com/example/attendancemgr/data/LoginDataSource.java
@@ -0,0 +1,63 @@
+package com.example.attendancemgr.data;
+
+import android.content.SharedPreferences;
+import android.os.AsyncTask;
+
+import androidx.annotation.NonNull;
+
+import com.example.attendancemgr.MainActivity2;
+import com.example.attendancemgr.data.model.LoggedInUser;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLEncoder;
+import java.util.ArrayList;
+
+import static android.content.Context.MODE_PRIVATE;
+import static com.example.attendancemgr.MainActivity2.AVAILABLE_JOBS;
+import static com.example.attendancemgr.MainActivity2.JOBS_FILE;
+import static com.example.attendancemgr.MainActivity2.NO_DATA;
+
+/**
+ * Class that handles authentication w/ login credentials and retrieves user information.
+ */
+public class LoginDataSource {
+ boolean dataBack;
+
+ public static final String DEFAULT_ID = "id";
+ public static final String DEFAULT_DISPLAY_NAME = "display name";
+
+ public Result login(String username, String password, String isFirst) {
+
+ try {
+
+ return new Result.Success(null);
+
+
+ } catch (Exception e) {
+ return new Result.Error(new IOException("Error logging in", e));
+ }
+ }
+
+ public void logout() {
+ }
+
+
+private static class InvalidUserException extends Exception{
+ @NonNull
+ @Override
+ public String toString() {
+ return "Invalid Username or Password";
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/attendancemgr/data/LoginRepository.java b/app/src/main/java/com/example/attendancemgr/data/LoginRepository.java
new file mode 100644
index 0000000..98d8109
--- /dev/null
+++ b/app/src/main/java/com/example/attendancemgr/data/LoginRepository.java
@@ -0,0 +1,54 @@
+package com.example.attendancemgr.data;
+
+import com.example.attendancemgr.data.model.LoggedInUser;
+
+/**
+ * Class that requests authentication and user information from the remote data source and
+ * maintains an in-memory cache of login status and user credentials information.
+ */
+public class LoginRepository {
+
+ private static volatile LoginRepository instance;
+
+ private LoginDataSource dataSource;
+
+ // If user credentials will be cached in local storage, it is recommended it be encrypted
+ // @see https://developer.android.com/training/articles/keystore
+ private LoggedInUser user = null;
+
+ // private constructor : singleton access
+ private LoginRepository(LoginDataSource dataSource) {
+ this.dataSource = dataSource;
+ }
+
+ public static LoginRepository getInstance(LoginDataSource dataSource) {
+ if (instance == null) {
+ instance = new LoginRepository(dataSource);
+ }
+ return instance;
+ }
+
+ public boolean isLoggedIn() {
+ return user != null;
+ }
+
+ public void logout() {
+ user = null;
+ dataSource.logout();
+ }
+
+ private void setLoggedInUser(LoggedInUser user) {
+ this.user = user;
+ // If user credentials will be cached in local storage, it is recommended it be encrypted
+ // @see https://developer.android.com/training/articles/keystore
+ }
+
+ public Result login(String username, String password, String isFirst) {
+ // handle login
+ Result result = dataSource.login(username, password, isFirst);
+ if (result instanceof Result.Success) {
+ setLoggedInUser(((Result.Success) result).getData());
+ }
+ return result;
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/attendancemgr/data/Result.java b/app/src/main/java/com/example/attendancemgr/data/Result.java
new file mode 100644
index 0000000..b41f497
--- /dev/null
+++ b/app/src/main/java/com/example/attendancemgr/data/Result.java
@@ -0,0 +1,48 @@
+package com.example.attendancemgr.data;
+
+/**
+ * A generic class that holds a result success w/ data or an error exception.
+ */
+public class Result {
+ // hide the private constructor to limit subclass types (Success, Error)
+ private Result() {
+ }
+
+ @Override
+ public String toString() {
+ if (this instanceof Result.Success) {
+ Result.Success success = (Result.Success) this;
+ return "Success[data=" + success.getData().toString() + "]";
+ } else if (this instanceof Result.Error) {
+ Result.Error error = (Result.Error) this;
+ return "Error[exception=" + error.getError().toString() + "]";
+ }
+ return "";
+ }
+
+ // Success sub-class
+ public final static class Success extends Result {
+ private T data;
+
+ public Success(T data) {
+ this.data = data;
+ }
+
+ public T getData() {
+ return this.data;
+ }
+ }
+
+ // Error sub-class
+ public final static class Error extends Result {
+ private Exception error;
+
+ public Error(Exception error) {
+ this.error = error;
+ }
+
+ public Exception getError() {
+ return this.error;
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/attendancemgr/data/model/CoursesModel.java b/app/src/main/java/com/example/attendancemgr/data/model/CoursesModel.java
new file mode 100644
index 0000000..74e817a
--- /dev/null
+++ b/app/src/main/java/com/example/attendancemgr/data/model/CoursesModel.java
@@ -0,0 +1,16 @@
+package com.example.attendancemgr.data.model;
+
+public class CoursesModel {
+ private String mCourse;
+ public CoursesModel(String course) {
+ this.mCourse = course;
+ }
+
+ public String getmCourse() {
+ return mCourse;
+ }
+
+ public void setmCourse(String mCourse) {
+ this.mCourse = mCourse;
+ }
+}
diff --git a/app/src/main/java/com/example/attendancemgr/data/model/DepartmentsModel.java b/app/src/main/java/com/example/attendancemgr/data/model/DepartmentsModel.java
new file mode 100644
index 0000000..c5c2b28
--- /dev/null
+++ b/app/src/main/java/com/example/attendancemgr/data/model/DepartmentsModel.java
@@ -0,0 +1,19 @@
+package com.example.attendancemgr.data.model;
+
+public class DepartmentsModel {
+ private String mDept;
+
+ public DepartmentsModel(String deptName) {
+ this.mDept = deptName;
+ }
+
+ public String getmDept() {
+ return mDept;
+ }
+
+ public void setmDept(String mDept1) {
+ this.mDept = mDept1;
+ }
+
+
+}
diff --git a/app/src/main/java/com/example/attendancemgr/data/model/LoggedInUser.java b/app/src/main/java/com/example/attendancemgr/data/model/LoggedInUser.java
new file mode 100644
index 0000000..fb5de21
--- /dev/null
+++ b/app/src/main/java/com/example/attendancemgr/data/model/LoggedInUser.java
@@ -0,0 +1,19 @@
+package com.example.attendancemgr.data.model;
+
+/**
+ * Data class that captures user information for logged in users retrieved from LoginRepository
+ */
+public class LoggedInUser {
+ private String mData;
+
+
+
+public LoggedInUser(String data){
+ this.mData = data;
+}
+ public String getmData() {
+ return mData;
+ }
+
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/attendancemgr/database/AgentCourse.java b/app/src/main/java/com/example/attendancemgr/database/AgentCourse.java
new file mode 100644
index 0000000..97e2d9b
--- /dev/null
+++ b/app/src/main/java/com/example/attendancemgr/database/AgentCourse.java
@@ -0,0 +1,100 @@
+package com.example.attendancemgr.database;
+
+
+import androidx.annotation.NonNull;
+import androidx.room.ColumnInfo;
+import androidx.room.Entity;
+import androidx.room.PrimaryKey;
+
+@Entity(tableName = "AgentCourse_table")
+public class AgentCourse {
+ public enum Att_Status {
+ open, closed
+ }
+ public enum Sub_Status {
+ submitted, unsubmitted
+ }
+ @PrimaryKey(autoGenerate = true)
+ private int id;
+
+ @NonNull
+ @ColumnInfo(name = "faculty")
+ private String faculty;
+
+ @NonNull
+ public String getFaculty() {
+ return faculty;
+ }
+
+ public void setFaculty(@NonNull String faculty) {
+ this.faculty = faculty;
+ }
+
+ @NonNull
+ @ColumnInfo(name = "department")
+ private String dept;
+
+ @NonNull
+ @ColumnInfo(name = "course")
+ private String course;
+
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ @ColumnInfo(name = "attendance_status")
+ private Att_Status att_status;
+
+ @ColumnInfo(name = "submission_status")
+ private Sub_Status sub_status;
+
+ @NonNull
+ public String getDept() {
+ return dept;
+ }
+
+ public void setDept(@NonNull String dept) {
+ this.dept = dept;
+ }
+
+ public void setCourse(@NonNull String course) {
+ this.course = course;
+ }
+
+ public AgentCourse(@NonNull String faculty, @NonNull String dept, @NonNull String course, Att_Status att_status, Sub_Status sub_status){
+ this.faculty = faculty;
+ this.dept = dept;
+ this.course = course;
+ this.att_status = att_status;
+ this.sub_status = sub_status;
+
+ }
+
+ @NonNull
+ public String getCourse() {
+ return course;
+ }
+
+
+
+ public AgentCourse.Att_Status getAtt_status() {
+ return att_status;
+ }
+
+ public void setAtt_status(AgentCourse.Att_Status att_status) {
+ this.att_status = att_status;
+ }
+
+ public AgentCourse.Sub_Status getSub_status() {
+ return sub_status;
+ }
+
+ public void setSub_status(AgentCourse.Sub_Status sub_status) {
+ this.sub_status = sub_status;
+ }
+}
diff --git a/app/src/main/java/com/example/attendancemgr/database/AttendanceCourse.java b/app/src/main/java/com/example/attendancemgr/database/AttendanceCourse.java
new file mode 100644
index 0000000..180a08c
--- /dev/null
+++ b/app/src/main/java/com/example/attendancemgr/database/AttendanceCourse.java
@@ -0,0 +1,142 @@
+package com.example.attendancemgr.database;
+
+import androidx.annotation.NonNull;
+import androidx.room.ColumnInfo;
+import androidx.room.Entity;
+import androidx.room.Ignore;
+import androidx.room.PrimaryKey;
+
+@Entity(tableName = "AttendanceCourse_table")
+public class AttendanceCourse {
+ public enum Sub_Status {
+ submitted, unsubmitted
+ }
+ public enum Cap_Status {
+ captured, uncaptured
+ }
+ @NonNull
+ @ColumnInfo(name = "course")
+ private String course;
+
+ @PrimaryKey(autoGenerate = true)
+ private int id;
+
+ @ColumnInfo(name = "sub_status")
+ private Sub_Status sub_status;
+
+ @ColumnInfo(name = "cap_status")
+ private Cap_Status cap_status;
+
+ @ColumnInfo(name = "admission_number")
+ private String Adm_No;
+
+ @ColumnInfo(name = "fingerprint")
+ private byte[] FP;
+
+ @ColumnInfo(name = "date")
+ private String Date;
+
+ @ColumnInfo(name = "period")
+ private int period;
+ public AttendanceCourse(@NonNull String course, String Adm_No, byte[] FP, Sub_Status sub_status, Cap_Status cap_status, String Date, int period){
+ this.course = course;
+ this.sub_status = sub_status;
+ this.Adm_No = Adm_No;
+ this.FP = FP;
+ this.cap_status = cap_status;
+ this.Date = Date;
+ this.period = period;
+ }
+
+ @Ignore
+public AttendanceCourse(int id, @NonNull String course, String admNo, byte[] fp, Sub_Status status, Cap_Status cap_status, String Date, int period){
+ this.course = course;
+ this.sub_status = status;
+ this.Adm_No = admNo;
+ this.FP = fp;
+ this.id = id;
+ this.cap_status = cap_status;
+ this.Date = Date;
+ this.period = period;
+
+}
+ @NonNull
+ public String getCourse() {
+ return course;
+ }
+
+ public String getAdmNo() {
+ return Adm_No;
+ }
+
+ public void setAdmNo(String AdmNo) {
+ this.Adm_No = AdmNo;
+ }
+
+ public int getPeriod() {
+ return period;
+ }
+
+ public void setPeriod(int period) {
+ this.period = period;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public byte[] getFP() {
+ return FP;
+ }
+
+ public Cap_Status getCap_status() {
+ return cap_status;
+ }
+
+ public void setCap_status(Cap_Status cap_status) {
+ this.cap_status = cap_status;
+ }
+
+ public void setFP(byte[] fp) {
+ FP = fp;
+ }
+
+ public Sub_Status getSub_Status() {
+ return sub_status;
+ }
+
+ public void setSub_Status(Sub_Status sub_status) {
+ this.sub_status = sub_status;
+ }
+
+ public Sub_Status getSub_status() {
+ return sub_status;
+ }
+
+ public String getAdm_No() {
+ return Adm_No;
+ }
+ public void setSub_status(Sub_Status sub_status) {
+ this.sub_status = sub_status;
+ }
+
+ public void setAdm_No(String adm_No) {
+ Adm_No = adm_No;
+ }
+
+ public void setCourse(@NonNull String course) {
+ this.course = course;
+ }
+
+ public String getDate() {
+ return Date;
+ }
+
+ public void setDate(String date) {
+ Date = date;
+ }
+}
diff --git a/app/src/main/java/com/example/attendancemgr/database/CourseDao.java b/app/src/main/java/com/example/attendancemgr/database/CourseDao.java
new file mode 100644
index 0000000..66c11d6
--- /dev/null
+++ b/app/src/main/java/com/example/attendancemgr/database/CourseDao.java
@@ -0,0 +1,62 @@
+package com.example.attendancemgr.database;
+
+import androidx.lifecycle.LiveData;
+import androidx.room.Dao;
+import androidx.room.Delete;
+import androidx.room.Insert;
+import androidx.room.OnConflictStrategy;
+import androidx.room.Query;
+import androidx.room.Update;
+
+import java.util.LinkedList;
+import java.util.List;
+@Dao
+public interface CourseDao {
+ @Insert(onConflict = OnConflictStrategy.IGNORE)
+ void insert(AgentCourse agCourse);
+
+ @Insert(onConflict = OnConflictStrategy.IGNORE)
+ void insert(AttendanceCourse atCourse);
+
+ @Insert(onConflict = OnConflictStrategy.IGNORE)
+ void insert(EnrolCourse enCourse);
+
+ @Query("DELETE FROM AgentCourse_table")
+ void deleteAllAgentCourse();
+
+ @Query("DELETE FROM AttendanceCourse_table")
+ void deleteAllAttendanceCourse();
+
+ @Query("DELETE FROM EnrolCourse_table")
+ void deleteAllEnrolCourse();
+
+ @Delete
+ void deleteAgentCourse(AgentCourse agCourse);
+
+ @Delete
+ void deleteAttendanceCourse(AttendanceCourse atCourse);
+
+ @Delete
+ void deleteEnrolCourse(EnrolCourse enCourse);
+
+ @Query("SELECT * from AgentCourse_table ORDER BY course ASC")
+ LiveData> getAllAgentCourses();
+
+ @Query("SELECT * from AttendanceCourse_table WHERE sub_status == 'unsubmitted' ORDER BY course ASC")
+ LiveData> getAllAttendanceCourses();
+
+ @Query("SELECT * from EnrolCourse_table WHERE status == 'unsubmitted' ORDER BY course ASC")
+ LiveData> getAllEnrolCourses();
+
+ @Update
+ void update(AgentCourse... courses);
+
+ @Update()
+ void update(AttendanceCourse... courses);
+
+ @Update
+ void update(EnrolCourse... courses);
+
+ @Query("SELECT * from AgentCourse_table LIMIT 1")
+ AgentCourse[] getAnyCourse();
+}
diff --git a/app/src/main/java/com/example/attendancemgr/database/CourseRepository.java b/app/src/main/java/com/example/attendancemgr/database/CourseRepository.java
new file mode 100644
index 0000000..23c0064
--- /dev/null
+++ b/app/src/main/java/com/example/attendancemgr/database/CourseRepository.java
@@ -0,0 +1,176 @@
+package com.example.attendancemgr.database;
+
+import android.app.Application;
+import android.os.AsyncTask;
+
+import androidx.lifecycle.LiveData;
+
+import java.util.List;
+
+public class CourseRepository {
+ private CourseDao mCourseDao;
+ private LiveData> mAllAgentCourses;
+ private LiveData> mAllEnrolCourses;
+ private LiveData> mAllAttendanceCourses;
+
+ CourseRepository(Application application) {
+ CourseRoomDatabase db = CourseRoomDatabase.getDatabase(application);
+ mCourseDao = db.courseDao();
+ mAllAgentCourses = mCourseDao.getAllAgentCourses();
+ mAllAttendanceCourses = mCourseDao.getAllAttendanceCourses();
+ mAllEnrolCourses = mCourseDao.getAllEnrolCourses();
+ }
+ LiveData> getAllAgentCourses() {
+ return mAllAgentCourses;
+ }
+ LiveData> getAllEnrolCourses() {
+ return mAllEnrolCourses;
+ }
+ LiveData> getAllAttendanceCourses() {
+ return mAllAttendanceCourses;
+ }
+
+ public void insert(AgentCourse course) {
+ new insertAsyncTask(mCourseDao).execute(course);
+ }
+ public void insert(AttendanceCourse course) {
+ new insertAsyncTask(mCourseDao).execute(course);
+ }
+ public void insert(EnrolCourse course) {
+ new insertAsyncTask(mCourseDao).execute(course);
+ }
+
+ public void update(AgentCourse course) {
+ new updateCourseAsyncTask(mCourseDao).execute(course);
+ }
+ public void update(AttendanceCourse course) {
+ new updateCourseAsyncTask(mCourseDao).execute(course);
+ }
+ public void update(EnrolCourse course) {
+ new updateCourseAsyncTask(mCourseDao).execute(course);
+ }
+
+ public void deleteAllAgentCourses() {
+ new deleteAllAgentCoursesAsyncTask(mCourseDao).execute();
+ }
+ public void deleteAllAttendanceCourses() {
+ new deleteAllAttendanceCoursesAsyncTask(mCourseDao).execute();
+ }
+ public void deleteAllEnrolCourses() {
+ new deleteAllEnrolCoursesAsyncTask(mCourseDao).execute();
+ }
+
+ public void deleteAgentCourse(AgentCourse course) {
+ new deleteCourseAsyncTask(mCourseDao).execute(course);
+ }
+ public void deleteAttendanceCourse(AttendanceCourse course) {
+ new deleteCourseAsyncTask(mCourseDao).execute(course);
+ }
+ public void deleteEnrolCourse(EnrolCourse course) {
+ new deleteCourseAsyncTask(mCourseDao).execute(course);
+ }
+ public AgentCourse[] getAnyCourse(){
+ return mCourseDao.getAnyCourse();
+ }
+ private static class insertAsyncTask extends AsyncTask