Browse Source

first commit

Chris Cromer 1 year ago
commit
4b9235a7b2
100 changed files with 10725 additions and 0 deletions
  1. 8
    0
      .gitignore
  2. 1
    0
      .idea/.name
  3. 22
    0
      .idea/compiler.xml
  4. 3
    0
      .idea/copyright/profiles_settings.xml
  5. 3
    0
      .idea/dictionaries/cromer.xml
  6. 6
    0
      .idea/encodings.xml
  7. 19
    0
      .idea/gradle.xml
  8. 36
    0
      .idea/misc.xml
  9. 9
    0
      .idea/modules.xml
  10. 12
    0
      .idea/runConfigurations.xml
  11. 15
    0
      .navigation/attendance-ubb/raw/main.nvg.xml
  12. 1
    0
      attendance-ubb/.gitignore
  13. 45
    0
      attendance-ubb/build.gradle
  14. BIN
      attendance-ubb/libs/poi-3.14-beta1-20151223.jar
  15. 27
    0
      attendance-ubb/proguard-rules.pro
  16. 123
    0
      attendance-ubb/src/main/AndroidManifest.xml
  17. 44
    0
      attendance-ubb/src/main/java/cl/cromer/ubb/attendance/About.java
  18. 60
    0
      attendance-ubb/src/main/java/cl/cromer/ubb/attendance/Attendance.java
  19. 122
    0
      attendance-ubb/src/main/java/cl/cromer/ubb/attendance/Class.java
  20. 1056
    0
      attendance-ubb/src/main/java/cl/cromer/ubb/attendance/ClassList.java
  21. 77
    0
      attendance-ubb/src/main/java/cl/cromer/ubb/attendance/ClassListAdapter.java
  22. 968
    0
      attendance-ubb/src/main/java/cl/cromer/ubb/attendance/ClassReport.java
  23. 508
    0
      attendance-ubb/src/main/java/cl/cromer/ubb/attendance/CorrectAttendance.java
  24. 126
    0
      attendance-ubb/src/main/java/cl/cromer/ubb/attendance/Course.java
  25. 976
    0
      attendance-ubb/src/main/java/cl/cromer/ubb/attendance/CourseList.java
  26. 80
    0
      attendance-ubb/src/main/java/cl/cromer/ubb/attendance/CourseListAdapter.java
  27. 867
    0
      attendance-ubb/src/main/java/cl/cromer/ubb/attendance/CourseReport.java
  28. 80
    0
      attendance-ubb/src/main/java/cl/cromer/ubb/attendance/DBSchema.java
  29. 171
    0
      attendance-ubb/src/main/java/cl/cromer/ubb/attendance/Excel.java
  30. 264
    0
      attendance-ubb/src/main/java/cl/cromer/ubb/attendance/FileSystem.java
  31. 751
    0
      attendance-ubb/src/main/java/cl/cromer/ubb/attendance/ImportExcel.java
  32. 411
    0
      attendance-ubb/src/main/java/cl/cromer/ubb/attendance/ImportPhotos.java
  33. 508
    0
      attendance-ubb/src/main/java/cl/cromer/ubb/attendance/LateStudentAttendance.java
  34. 11
    0
      attendance-ubb/src/main/java/cl/cromer/ubb/attendance/ListenerDownload.java
  35. 81
    0
      attendance-ubb/src/main/java/cl/cromer/ubb/attendance/Major.java
  36. 175
    0
      attendance-ubb/src/main/java/cl/cromer/ubb/attendance/Progress.java
  37. 194
    0
      attendance-ubb/src/main/java/cl/cromer/ubb/attendance/RUT.java
  38. 51
    0
      attendance-ubb/src/main/java/cl/cromer/ubb/attendance/RecyclerClickListener.java
  39. 155
    0
      attendance-ubb/src/main/java/cl/cromer/ubb/attendance/SQLParser.java
  40. 29
    0
      attendance-ubb/src/main/java/cl/cromer/ubb/attendance/StaticVariables.java
  41. 27
    0
      attendance-ubb/src/main/java/cl/cromer/ubb/attendance/StringFixer.java
  42. 113
    0
      attendance-ubb/src/main/java/cl/cromer/ubb/attendance/Student.java
  43. 104
    0
      attendance-ubb/src/main/java/cl/cromer/ubb/attendance/Subject.java
  44. 1584
    0
      attendance-ubb/src/main/java/cl/cromer/ubb/attendance/SubjectList.java
  45. 96
    0
      attendance-ubb/src/main/java/cl/cromer/ubb/attendance/SubjectListAdapter.java
  46. 572
    0
      attendance-ubb/src/main/java/cl/cromer/ubb/attendance/TakeAttendance.java
  47. 7
    0
      attendance-ubb/src/main/java/cl/cromer/ubb/attendance/TakeAttendanceListener.java
  48. 57
    0
      attendance-ubb/src/main/java/cl/cromer/ubb/attendance/ZipFile.java
  49. 16
    0
      attendance-ubb/src/main/res/anim/expand.xml
  50. 6
    0
      attendance-ubb/src/main/res/anim/hold_back.xml
  51. 5
    0
      attendance-ubb/src/main/res/anim/push_down_in.xml
  52. 6
    0
      attendance-ubb/src/main/res/anim/push_right_out.xml
  53. 12
    0
      attendance-ubb/src/main/res/anim/rotate.xml
  54. 16
    0
      attendance-ubb/src/main/res/anim/shrink.xml
  55. BIN
      attendance-ubb/src/main/res/drawable-hdpi-v11/ic_stat_ubb.png
  56. BIN
      attendance-ubb/src/main/res/drawable-hdpi/ic_stat_ubb.png
  57. BIN
      attendance-ubb/src/main/res/drawable-hdpi/ic_ubb.png
  58. BIN
      attendance-ubb/src/main/res/drawable-hdpi/ubb_logo.png
  59. BIN
      attendance-ubb/src/main/res/drawable-hdpi/ubbtheme_btn_default_disabled_focused_holo_light.9.png
  60. BIN
      attendance-ubb/src/main/res/drawable-hdpi/ubbtheme_btn_default_disabled_holo_light.9.png
  61. BIN
      attendance-ubb/src/main/res/drawable-hdpi/ubbtheme_btn_default_focused_holo_light.9.png
  62. BIN
      attendance-ubb/src/main/res/drawable-hdpi/ubbtheme_btn_default_normal_holo_light.9.png
  63. BIN
      attendance-ubb/src/main/res/drawable-hdpi/ubbtheme_btn_default_pressed_holo_light.9.png
  64. BIN
      attendance-ubb/src/main/res/drawable-hdpi/ubbtheme_list_focused_holo.9.png
  65. BIN
      attendance-ubb/src/main/res/drawable-hdpi/ubbtheme_list_longpressed_holo.9.png
  66. BIN
      attendance-ubb/src/main/res/drawable-hdpi/ubbtheme_list_pressed_holo_light.9.png
  67. BIN
      attendance-ubb/src/main/res/drawable-hdpi/ubbtheme_list_selector_disabled_holo_light.9.png
  68. BIN
      attendance-ubb/src/main/res/drawable-hdpi/ubbtheme_spinner_default_holo_light.9.png
  69. BIN
      attendance-ubb/src/main/res/drawable-hdpi/ubbtheme_spinner_disabled_holo_light.9.png
  70. BIN
      attendance-ubb/src/main/res/drawable-hdpi/ubbtheme_spinner_focused_holo_light.9.png
  71. BIN
      attendance-ubb/src/main/res/drawable-hdpi/ubbtheme_spinner_pressed_holo_light.9.png
  72. BIN
      attendance-ubb/src/main/res/drawable-hdpi/ubbtheme_textfield_activated_holo_light.9.png
  73. BIN
      attendance-ubb/src/main/res/drawable-hdpi/ubbtheme_textfield_default_holo_light.9.png
  74. BIN
      attendance-ubb/src/main/res/drawable-hdpi/ubbtheme_textfield_disabled_focused_holo_light.9.png
  75. BIN
      attendance-ubb/src/main/res/drawable-hdpi/ubbtheme_textfield_disabled_holo_light.9.png
  76. BIN
      attendance-ubb/src/main/res/drawable-hdpi/ubbtheme_textfield_focused_holo_light.9.png
  77. BIN
      attendance-ubb/src/main/res/drawable-mdpi-v11/ic_stat_ubb.png
  78. BIN
      attendance-ubb/src/main/res/drawable-mdpi/ic_stat_ubb.png
  79. BIN
      attendance-ubb/src/main/res/drawable-mdpi/ic_ubb.png
  80. BIN
      attendance-ubb/src/main/res/drawable-mdpi/ubb_logo.png
  81. BIN
      attendance-ubb/src/main/res/drawable-mdpi/ubbtheme_btn_default_disabled_focused_holo_light.9.png
  82. BIN
      attendance-ubb/src/main/res/drawable-mdpi/ubbtheme_btn_default_disabled_holo_light.9.png
  83. BIN
      attendance-ubb/src/main/res/drawable-mdpi/ubbtheme_btn_default_focused_holo_light.9.png
  84. BIN
      attendance-ubb/src/main/res/drawable-mdpi/ubbtheme_btn_default_normal_holo_light.9.png
  85. BIN
      attendance-ubb/src/main/res/drawable-mdpi/ubbtheme_btn_default_pressed_holo_light.9.png
  86. BIN
      attendance-ubb/src/main/res/drawable-mdpi/ubbtheme_list_focused_holo.9.png
  87. BIN
      attendance-ubb/src/main/res/drawable-mdpi/ubbtheme_list_longpressed_holo.9.png
  88. BIN
      attendance-ubb/src/main/res/drawable-mdpi/ubbtheme_list_pressed_holo_light.9.png
  89. BIN
      attendance-ubb/src/main/res/drawable-mdpi/ubbtheme_list_selector_disabled_holo_light.9.png
  90. BIN
      attendance-ubb/src/main/res/drawable-mdpi/ubbtheme_spinner_default_holo_light.9.png
  91. BIN
      attendance-ubb/src/main/res/drawable-mdpi/ubbtheme_spinner_disabled_holo_light.9.png
  92. BIN
      attendance-ubb/src/main/res/drawable-mdpi/ubbtheme_spinner_focused_holo_light.9.png
  93. BIN
      attendance-ubb/src/main/res/drawable-mdpi/ubbtheme_spinner_pressed_holo_light.9.png
  94. BIN
      attendance-ubb/src/main/res/drawable-mdpi/ubbtheme_textfield_activated_holo_light.9.png
  95. BIN
      attendance-ubb/src/main/res/drawable-mdpi/ubbtheme_textfield_default_holo_light.9.png
  96. BIN
      attendance-ubb/src/main/res/drawable-mdpi/ubbtheme_textfield_disabled_focused_holo_light.9.png
  97. BIN
      attendance-ubb/src/main/res/drawable-mdpi/ubbtheme_textfield_disabled_holo_light.9.png
  98. BIN
      attendance-ubb/src/main/res/drawable-mdpi/ubbtheme_textfield_focused_holo_light.9.png
  99. 9
    0
      attendance-ubb/src/main/res/drawable-v21/ic_menu_add.xml
  100. 0
    0
      attendance-ubb/src/main/res/drawable-v21/ic_menu_correct.xml

+ 8
- 0
.gitignore View File

@@ -0,0 +1,8 @@
1
+*.iml
2
+.gradle
3
+/local.properties
4
+/.idea/workspace.xml
5
+/.idea/libraries
6
+.DS_Store
7
+/build
8
+/captures

+ 1
- 0
.idea/.name View File

@@ -0,0 +1 @@
1
+UBBAttendance

+ 22
- 0
.idea/compiler.xml View File

@@ -0,0 +1,22 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<project version="4">
3
+  <component name="CompilerConfiguration">
4
+    <resourceExtensions />
5
+    <wildcardResourcePatterns>
6
+      <entry name="!?*.java" />
7
+      <entry name="!?*.form" />
8
+      <entry name="!?*.class" />
9
+      <entry name="!?*.groovy" />
10
+      <entry name="!?*.scala" />
11
+      <entry name="!?*.flex" />
12
+      <entry name="!?*.kt" />
13
+      <entry name="!?*.clj" />
14
+      <entry name="!?*.aj" />
15
+    </wildcardResourcePatterns>
16
+    <annotationProcessing>
17
+      <profile default="true" name="Default" enabled="false">
18
+        <processorPath useClasspath="true" />
19
+      </profile>
20
+    </annotationProcessing>
21
+  </component>
22
+</project>

+ 3
- 0
.idea/copyright/profiles_settings.xml View File

@@ -0,0 +1,3 @@
1
+<component name="CopyrightManager">
2
+  <settings default="" />
3
+</component>

+ 3
- 0
.idea/dictionaries/cromer.xml View File

@@ -0,0 +1,3 @@
1
+<component name="ProjectDictionaryState">
2
+  <dictionary name="cromer" />
3
+</component>

+ 6
- 0
.idea/encodings.xml View File

@@ -0,0 +1,6 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<project version="4">
3
+  <component name="Encoding">
4
+    <file url="PROJECT" charset="UTF-8" />
5
+  </component>
6
+</project>

+ 19
- 0
.idea/gradle.xml View File

@@ -0,0 +1,19 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<project version="4">
3
+  <component name="GradleSettings">
4
+    <option name="linkedExternalProjectsSettings">
5
+      <GradleProjectSettings>
6
+        <option name="distributionType" value="DEFAULT_WRAPPED" />
7
+        <option name="externalProjectPath" value="$PROJECT_DIR$" />
8
+        <option name="gradleJvm" value="1.7" />
9
+        <option name="modules">
10
+          <set>
11
+            <option value="$PROJECT_DIR$" />
12
+            <option value="$PROJECT_DIR$/attendance-ubb" />
13
+          </set>
14
+        </option>
15
+        <option name="resolveModulePerSourceSet" value="false" />
16
+      </GradleProjectSettings>
17
+    </option>
18
+  </component>
19
+</project>

+ 36
- 0
.idea/misc.xml View File

@@ -0,0 +1,36 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<project version="4">
3
+  <component name="EntryPointsManager">
4
+    <entry_points version="2.0" />
5
+  </component>
6
+  <component name="NullableNotNullManager">
7
+    <option name="myDefaultNullable" value="android.support.annotation.Nullable" />
8
+    <option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
9
+    <option name="myNullables">
10
+      <value>
11
+        <list size="4">
12
+          <item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
13
+          <item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
14
+          <item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
15
+          <item index="3" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
16
+        </list>
17
+      </value>
18
+    </option>
19
+    <option name="myNotNulls">
20
+      <value>
21
+        <list size="4">
22
+          <item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
23
+          <item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
24
+          <item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
25
+          <item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
26
+        </list>
27
+      </value>
28
+    </option>
29
+  </component>
30
+  <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
31
+    <output url="file://$PROJECT_DIR$/build/classes" />
32
+  </component>
33
+  <component name="ProjectType">
34
+    <option name="id" value="Android" />
35
+  </component>
36
+</project>

+ 9
- 0
.idea/modules.xml View File

@@ -0,0 +1,9 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<project version="4">
3
+  <component name="ProjectModuleManager">
4
+    <modules>
5
+      <module fileurl="file://$PROJECT_DIR$/UBBAttendance.iml" filepath="$PROJECT_DIR$/UBBAttendance.iml" />
6
+      <module fileurl="file://$PROJECT_DIR$/attendance-ubb/attendance-ubb.iml" filepath="$PROJECT_DIR$/attendance-ubb/attendance-ubb.iml" />
7
+    </modules>
8
+  </component>
9
+</project>

+ 12
- 0
.idea/runConfigurations.xml View File

@@ -0,0 +1,12 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<project version="4">
3
+  <component name="RunConfigurationProducerService">
4
+    <option name="ignoredProducers">
5
+      <set>
6
+        <option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
7
+        <option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
8
+        <option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
9
+      </set>
10
+    </option>
11
+  </component>
12
+</project>

+ 15
- 0
.navigation/attendance-ubb/raw/main.nvg.xml View File

@@ -0,0 +1,15 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<navigationModel
3
+  ns = "http://schemas.android.com?import=com.android.tools.idea.editors.navigation.model.*">
4
+  <locations
5
+    class = "java.util.ArrayList">
6
+    <statePointEntry>
7
+      <state
8
+        class = "com.android.tools.idea.editors.navigation.model.ActivityState"
9
+        className = "cl.cromer.attendance.SubjectList"/>
10
+      <point
11
+        x = "196"
12
+        y = "52"/>
13
+    </statePointEntry>
14
+  </locations>
15
+</navigationModel>

+ 1
- 0
attendance-ubb/.gitignore View File

@@ -0,0 +1 @@
1
+/build

+ 45
- 0
attendance-ubb/build.gradle View File

@@ -0,0 +1,45 @@
1
+apply plugin: 'com.android.application'
2
+
3
+android {
4
+    signingConfigs {
5
+        cromer {
6
+            keyAlias 'cromer'
7
+            keyPassword 'K7PRxe4eyeXGr3FeULSapUEqHcKAZgkaGe6HmX7cNd873XBLwR'
8
+            storeFile file('/home/cromer/cromer_cl/keystore/keystore')
9
+            storePassword 'K7PRxe4eyeXGr3FeULSapUEqHcKAZgkaGe6HmX7cNd873XBLwR'
10
+        }
11
+    }
12
+    compileSdkVersion 27
13
+    buildToolsVersion "27"
14
+    defaultConfig {
15
+        applicationId "cl.cromer.ubb.attendance"
16
+        minSdkVersion 14
17
+        targetSdkVersion 27
18
+        versionCode 1
19
+        versionName "1.0"
20
+        signingConfig signingConfigs.cromer
21
+    }
22
+    buildTypes {
23
+        release {
24
+            minifyEnabled true
25
+            shrinkResources true
26
+            signingConfig signingConfigs.cromer
27
+            proguardFile '/home/cromer/StudioProjects/UBBAttendance/attendance-ubb/proguard-rules.pro'
28
+        }
29
+        debug {
30
+            debuggable true
31
+            jniDebuggable true
32
+            minifyEnabled false
33
+        }
34
+    }
35
+    productFlavors {
36
+    }
37
+}
38
+
39
+dependencies {
40
+    compile fileTree(include: ['*.jar'], dir: 'libs')
41
+    compile 'com.android.support:appcompat-v7:27.0.0'
42
+    compile 'com.android.support:design:27.0.0'
43
+    compile 'com.android.support:cardview-v7:27.0.0'
44
+    compile 'com.android.support:recyclerview-v7:27.0.0'
45
+}

BIN
attendance-ubb/libs/poi-3.14-beta1-20151223.jar View File


+ 27
- 0
attendance-ubb/proguard-rules.pro View File

@@ -0,0 +1,27 @@
1
+# Add project specific ProGuard rules here.
2
+# By default, the flags in this file are appended to flags specified
3
+# in /mnt/storage/Android/sdk/tools/proguard/proguard-android.txt
4
+# You can edit the include path and order by changing the proguardFiles
5
+# directive in build.gradle.
6
+#
7
+# For more details, see
8
+#   http://developer.android.com/guide/developing/tools/proguard.html
9
+
10
+# Add any project specific keep options here:
11
+
12
+# If your project uses WebView with JS, uncomment the following
13
+# and specify the fully qualified class name to the JavaScript interface
14
+# class:
15
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16
+#   public *;
17
+#}
18
+-keep public class org.apache.poi.** {*;}
19
+-dontwarn org.apache.poi.**
20
+
21
+-dontwarn android.support.v7.**
22
+-keep class android.support.v7.** { *; }
23
+-keep interface android.support.v7.** { *; }
24
+
25
+-dontwarn android.support.v4.**
26
+-keep class android.support.v4.** { *; }
27
+-keep interface android.support.v4.** { *; }

+ 123
- 0
attendance-ubb/src/main/AndroidManifest.xml View File

@@ -0,0 +1,123 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<manifest package="cl.cromer.ubb.attendance"
3
+          xmlns:android="http://schemas.android.com/apk/res/android">
4
+
5
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
6
+    <uses-permission android:name="android.permission.WAKE_LOCK"/>
7
+
8
+    <application
9
+        android:allowBackup="true"
10
+        android:icon="@mipmap/ic_launcher"
11
+        android:label="@string/app_name"
12
+        android:supportsRtl="true"
13
+        android:theme="@style/UBBTheme">
14
+        <activity
15
+            android:name=".SubjectList"
16
+            android:label="@string/app_name"
17
+            android:theme="@style/UBBTheme.NoActionBar">
18
+            <intent-filter>
19
+                <action android:name="android.intent.action.MAIN"/>
20
+
21
+                <category android:name="android.intent.category.LAUNCHER"/>
22
+            </intent-filter>
23
+        </activity>
24
+        <activity
25
+            android:name=".CourseList"
26
+            android:label="@string/app_name"
27
+            android:parentActivityName=".SubjectList"
28
+            android:theme="@style/UBBTheme">
29
+            <meta-data
30
+                android:name="android.support.PARENT_ACTIVITY"
31
+                android:value="cl.cromer.ubb.attendance.SubjectList"/>
32
+        </activity>
33
+        <activity
34
+            android:name=".ClassList"
35
+            android:label="@string/app_name"
36
+            android:parentActivityName=".CourseList"
37
+            android:theme="@style/UBBTheme">
38
+            <meta-data
39
+                android:name="android.support.PARENT_ACTIVITY"
40
+                android:value="cl.cromer.ubb.attendance.CourseList"/>
41
+        </activity>
42
+        <activity
43
+            android:name=".ImportExcel"
44
+            android:label="@string/app_name"
45
+            android:parentActivityName=".SubjectList"
46
+            android:screenOrientation="portrait"
47
+            android:theme="@style/UBBTheme">
48
+            <meta-data
49
+                android:name="android.support.PARENT_ACTIVITY"
50
+                android:value="cl.cromer.ubb.attendance.SubjectList"/>
51
+        </activity>
52
+        <activity
53
+            android:name=".ImportPhotos"
54
+            android:label="@string/app_name"
55
+            android:parentActivityName=".SubjectList"
56
+            android:screenOrientation="portrait"
57
+            android:theme="@style/UBBTheme">
58
+            <meta-data
59
+                android:name="android.support.PARENT_ACTIVITY"
60
+                android:value="cl.cromer.ubb.attendance.SubjectList"/>
61
+            >
62
+        </activity>
63
+        <activity
64
+            android:name=".TakeAttendance"
65
+            android:label="@string/app_name"
66
+            android:parentActivityName=".ClassList"
67
+            android:screenOrientation="portrait"
68
+            android:theme="@style/UBBTheme">
69
+            <meta-data
70
+                android:name="android.support.PARENT_ACTIVITY"
71
+                android:value="cl.cromer.ubb.attendance.ClassList"/>
72
+        </activity>
73
+        <activity
74
+            android:name=".CorrectAttendance"
75
+            android:label="@string/app_name"
76
+            android:parentActivityName=".ClassList"
77
+            android:theme="@style/UBBTheme">
78
+            <meta-data
79
+                android:name="android.support.PARENT_ACTIVITY"
80
+                android:value="cl.cromer.ubb.attendance.ClassList"/>
81
+        </activity>
82
+        <activity
83
+            android:name=".LateStudentAttendance"
84
+            android:label="@string/app_name"
85
+            android:parentActivityName=".ClassList"
86
+            android:theme="@style/UBBTheme">
87
+            <meta-data
88
+                android:name="android.support.PARENT_ACTIVITY"
89
+                android:value="cl.cromer.ubb.attendance.ClassList"/>
90
+        </activity>
91
+        <activity
92
+            android:name=".ClassReport"
93
+            android:label="@string/app_name"
94
+            android:parentActivityName=".SubjectList"
95
+            android:screenOrientation="portrait"
96
+            android:theme="@style/UBBTheme">
97
+            <meta-data
98
+                android:name="android.support.PARENT_ACTIVITY"
99
+                android:value="cl.cromer.ubb.attendance.SubjectList"/>
100
+        </activity>
101
+        <activity
102
+            android:name=".About"
103
+            android:label="@string/app_name"
104
+            android:parentActivityName=".SubjectList"
105
+            android:screenOrientation="portrait"
106
+            android:theme="@style/UBBTheme">
107
+            <meta-data
108
+                android:name="android.support.PARENT_ACTIVITY"
109
+                android:value="cl.cromer.ubb.attendance.SubjectList"/>
110
+        </activity>
111
+        <activity
112
+            android:name=".CourseReport"
113
+            android:label="@string/app_name"
114
+            android:parentActivityName=".SubjectList"
115
+            android:screenOrientation="portrait"
116
+            android:theme="@style/UBBTheme">
117
+            <meta-data
118
+                android:name="android.support.PARENT_ACTIVITY"
119
+                android:value="cl.cromer.ubb.attendance.SubjectList"/>
120
+        </activity>
121
+    </application>
122
+
123
+</manifest>

+ 44
- 0
attendance-ubb/src/main/java/cl/cromer/ubb/attendance/About.java View File

@@ -0,0 +1,44 @@
1
+package cl.cromer.ubb.attendance;
2
+
3
+import android.content.Intent;
4
+import android.net.Uri;
5
+import android.os.Bundle;
6
+import android.support.v7.app.ActionBar;
7
+import android.support.v7.app.AppCompatActivity;
8
+import android.support.v7.widget.Toolbar;
9
+import android.view.View;
10
+
11
+public class About extends AppCompatActivity {
12
+
13
+    @Override
14
+    protected void onCreate(Bundle savedInstanceState) {
15
+        super.onCreate(savedInstanceState);
16
+        setContentView(R.layout.activity_about);
17
+        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
18
+        setSupportActionBar(toolbar);
19
+        ActionBar actionBar = getSupportActionBar();
20
+        if (actionBar != null) {
21
+            actionBar.setHomeButtonEnabled(true);
22
+            actionBar.setDisplayHomeAsUpEnabled(true);
23
+        }
24
+    }
25
+
26
+    @Override
27
+    public void onBackPressed() {
28
+        super.onBackPressed();
29
+    }
30
+
31
+    @Override
32
+    public boolean onSupportNavigateUp() {
33
+        onBackPressed();
34
+        return true;
35
+    }
36
+
37
+    public void sendEmail(View view) {
38
+        Intent intent = new Intent(Intent.ACTION_SENDTO);
39
+        intent.setData(Uri.parse("mailto:"));
40
+        intent.putExtra(Intent.EXTRA_EMAIL, "chris@cromer.cl");
41
+        intent.putExtra(Intent.EXTRA_SUBJECT, "Attendance");
42
+        startActivity(Intent.createChooser(intent, getResources().getString(R.string.about_email)));
43
+    }
44
+}

+ 60
- 0
attendance-ubb/src/main/java/cl/cromer/ubb/attendance/Attendance.java View File

@@ -0,0 +1,60 @@
1
+package cl.cromer.ubb.attendance;
2
+
3
+public class Attendance extends Student {
4
+    private int status;
5
+    // 0 - uninitialized
6
+    // 1 - present
7
+    // 2 - justified
8
+    // 3 - absent
9
+    // 4 - late
10
+
11
+    private int present;
12
+    private int justified;
13
+    private int absent;
14
+    private int late;
15
+
16
+    public Attendance(int status, int studentId, String run, String firstName, String secondName, String firstLastName, String secondLastName, int major, int enrolled, String email, byte[] photo) {
17
+        super(studentId, run, firstName, secondName, firstLastName, secondLastName, major, enrolled, email, photo);
18
+        this.setStatus(status);
19
+    }
20
+
21
+    protected int getStatus() {
22
+        return status;
23
+    }
24
+
25
+    protected void setStatus(int status) {
26
+        this.status = status;
27
+    }
28
+
29
+    protected int getPresent() {
30
+        return present;
31
+    }
32
+
33
+    protected void setPresent(int present) {
34
+        this.present = present;
35
+    }
36
+
37
+    protected int getJustified() {
38
+        return justified;
39
+    }
40
+
41
+    protected void setJustified(int justified) {
42
+        this.justified = justified;
43
+    }
44
+
45
+    protected int getAbsent() {
46
+        return absent;
47
+    }
48
+
49
+    protected void setAbsent(int absent) {
50
+        this.absent = absent;
51
+    }
52
+
53
+    protected int getLate() {
54
+        return late;
55
+    }
56
+
57
+    protected void setLate(int late) {
58
+        this.late = late;
59
+    }
60
+}

+ 122
- 0
attendance-ubb/src/main/java/cl/cromer/ubb/attendance/Class.java View File

@@ -0,0 +1,122 @@
1
+package cl.cromer.ubb.attendance;
2
+
3
+import android.content.Context;
4
+import android.os.Parcel;
5
+import android.os.Parcelable;
6
+
7
+import java.text.DateFormat;
8
+import java.util.Calendar;
9
+
10
+public class Class extends Course implements Parcelable {
11
+    private int classId;
12
+    private long date;
13
+
14
+    public Class() {}
15
+
16
+    public Class(Course course, long date) {
17
+        super(course.getCourseId(), course.getCourseSection(), course.getCourseSemester(), course.getYear());
18
+        this.setDate(date);
19
+    }
20
+
21
+    public Class(Course course, int classId, long date) {
22
+        super(course.getCourseId(), course.getCourseSection(), course.getCourseSemester(), course.getYear());
23
+        this.setClassId(classId);
24
+        this.setDate(date);
25
+    }
26
+
27
+    protected void setClass(Class classObject) {
28
+        this.setClassId(classObject.getClassId());
29
+        this.setDate(classObject.getDate());
30
+    }
31
+
32
+    protected int getClassId() {
33
+        return classId;
34
+    }
35
+
36
+    protected void setClassId(int classId) {
37
+        this.classId = classId;
38
+    }
39
+
40
+    protected long getDate() {
41
+        return date;
42
+    }
43
+
44
+    protected void setDate(long date) {
45
+        // Remove the time, I only need the date
46
+        Calendar calendar = Calendar.getInstance();
47
+        calendar.setTimeInMillis(date);
48
+        calendar.set(Calendar.HOUR_OF_DAY, 0);
49
+        calendar.set(Calendar.MINUTE, 0);
50
+        calendar.set(Calendar.SECOND, 0);
51
+        calendar.set(Calendar.MILLISECOND, 0);
52
+        date = calendar.getTimeInMillis();
53
+
54
+        this.date = date;
55
+    }
56
+
57
+    protected String getFormattedDate(Context context) {
58
+        Calendar calendar = Calendar.getInstance();
59
+        calendar.setTimeInMillis(date);
60
+        DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.LONG, context.getResources().getConfiguration().locale);
61
+        return dateFormat.format(calendar.getTime());
62
+    }
63
+
64
+    protected String getFormattedShortDate(Context context) {
65
+        Calendar calendar = Calendar.getInstance();
66
+        calendar.setTimeInMillis(date);
67
+        DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.SHORT, context.getResources().getConfiguration().locale);
68
+        return dateFormat.format(calendar.getTime());
69
+    }
70
+
71
+    // Parcelable
72
+    @Override
73
+    public int describeContents() {
74
+        //Must be overridden, but I don't need it.
75
+        return 0;
76
+    }
77
+
78
+    @Override
79
+    public void writeToParcel(Parcel out, int flags) {
80
+        out.writeInt(majorId);
81
+        out.writeString(majorName);
82
+        out.writeInt(majorCode);
83
+        out.writeInt(subjectId);
84
+        out.writeInt(subjectCode);
85
+        out.writeString(subjectName);
86
+        out.writeInt(courseId);
87
+        out.writeInt(courseSection);
88
+        out.writeInt(courseSemester);
89
+        out.writeInt(courseYear);
90
+        out.writeInt(classId);
91
+        out.writeLong(date);
92
+    }
93
+
94
+    private void readFromParcel(Parcel in) {
95
+        majorId = in.readInt();
96
+        majorName = in.readString();
97
+        majorCode = in.readInt();
98
+        subjectId = in.readInt();
99
+        subjectCode = in.readInt();
100
+        subjectName = in.readString();
101
+        courseId = in.readInt();
102
+        courseSection = in.readInt();
103
+        courseSemester = in.readInt();
104
+        courseYear = in.readInt();
105
+        classId = in.readInt();
106
+        date = in.readLong();
107
+    }
108
+
109
+    private Class(Parcel in) {
110
+        readFromParcel(in);
111
+    }
112
+
113
+    public static final Parcelable.Creator<Class> CREATOR = new Parcelable.Creator<Class>() {
114
+        public Class createFromParcel(Parcel in) {
115
+            return new Class(in);
116
+        }
117
+
118
+        public Class[] newArray(int size) {
119
+            return new Class[size];
120
+        }
121
+    };
122
+}

+ 1056
- 0
attendance-ubb/src/main/java/cl/cromer/ubb/attendance/ClassList.java
File diff suppressed because it is too large
View File


+ 77
- 0
attendance-ubb/src/main/java/cl/cromer/ubb/attendance/ClassListAdapter.java View File

@@ -0,0 +1,77 @@
1
+package cl.cromer.ubb.attendance;
2
+
3
+import android.content.Context;
4
+import android.support.v7.widget.CardView;
5
+import android.support.v7.widget.RecyclerView;
6
+import android.view.LayoutInflater;
7
+import android.view.View;
8
+import android.view.ViewGroup;
9
+import android.widget.TextView;
10
+
11
+import java.util.List;
12
+
13
+public class ClassListAdapter extends RecyclerView.Adapter<ClassListAdapter.ClassViewHolder> {
14
+
15
+    private List<Class> classes;
16
+    private Context context;
17
+
18
+    public ClassListAdapter(List<Class> classes, Context context) {
19
+        this.classes = classes;
20
+        this.context = context;
21
+    }
22
+
23
+    @Override
24
+    public int getItemCount() {
25
+        return classes.size();
26
+    }
27
+
28
+    @Override
29
+    public ClassViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
30
+        View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.view_class_list_card, viewGroup, false);
31
+        return new ClassViewHolder(view);
32
+    }
33
+
34
+    @Override
35
+    public void onBindViewHolder(ClassViewHolder classViewHolder, int i) {
36
+        classViewHolder.classDate.setText(String.valueOf(classes.get(i).getFormattedDate(context)));
37
+        classViewHolder.classId.setText(String.valueOf(classes.get(i).getClassId()));
38
+        classViewHolder.itemView.setLongClickable(true);
39
+    }
40
+
41
+    @Override
42
+    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
43
+        super.onAttachedToRecyclerView(recyclerView);
44
+    }
45
+
46
+    public void addClass(Class classObject) {
47
+        classes.add(getItemCount(), classObject);
48
+        notifyItemInserted(getItemCount());
49
+    }
50
+
51
+    public void updateClass(int index, Class classObject) {
52
+        classes.set(index, classObject);
53
+        notifyItemChanged(index);
54
+    }
55
+
56
+    public Class getClass(int index) {
57
+        return classes.get(index);
58
+    }
59
+
60
+    public void deleteClass(Class classObject) {
61
+        classes.remove(classObject);
62
+    }
63
+
64
+    public static class ClassViewHolder extends RecyclerView.ViewHolder {
65
+        public CardView cardView;
66
+        public TextView classDate;
67
+        public TextView classId;
68
+
69
+        public ClassViewHolder(View itemView) {
70
+            super(itemView);
71
+            cardView = (CardView) itemView.findViewById(R.id.class_card_view);
72
+            classDate = (TextView) itemView.findViewById(R.id.class_date);
73
+            classId = (TextView) itemView.findViewById(R.id.class_id);
74
+        }
75
+    }
76
+
77
+}

+ 968
- 0
attendance-ubb/src/main/java/cl/cromer/ubb/attendance/ClassReport.java View File

@@ -0,0 +1,968 @@
1
+package cl.cromer.ubb.attendance;
2
+
3
+import android.content.ActivityNotFoundException;
4
+import android.content.Context;
5
+import android.content.DialogInterface;
6
+import android.content.Intent;
7
+import android.content.res.ColorStateList;
8
+import android.database.Cursor;
9
+import android.database.sqlite.SQLiteDatabase;
10
+import android.net.Uri;
11
+import android.os.AsyncTask;
12
+import android.os.Bundle;
13
+import android.os.Environment;
14
+import android.os.Handler;
15
+import android.os.PowerManager;
16
+import android.support.v4.content.ContextCompat;
17
+import android.support.v7.app.AlertDialog;
18
+import android.support.v7.app.AppCompatActivity;
19
+import android.util.Log;
20
+import android.view.LayoutInflater;
21
+import android.view.View;
22
+import android.widget.AdapterView;
23
+import android.widget.ArrayAdapter;
24
+import android.widget.RelativeLayout;
25
+import android.widget.Spinner;
26
+import android.widget.Toast;
27
+
28
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
29
+import org.apache.poi.ss.usermodel.Cell;
30
+import org.apache.poi.ss.usermodel.CellStyle;
31
+import org.apache.poi.ss.usermodel.Row;
32
+import org.apache.poi.ss.usermodel.Sheet;
33
+import org.apache.poi.ss.usermodel.Workbook;
34
+
35
+import java.io.File;
36
+import java.io.FileNotFoundException;
37
+import java.io.FileOutputStream;
38
+import java.io.IOException;
39
+import java.util.ArrayList;
40
+import java.util.List;
41
+
42
+import cl.cromer.ubb.attendance.Progress;
43
+import cl.cromer.ubb.attendance.DBSchema.*;
44
+
45
+public class ClassReport extends AppCompatActivity {
46
+
47
+    // SQLite database
48
+    private SQLParser sqlParser = null;
49
+    private SQLiteDatabase ubbDB = null;
50
+
51
+    // Background thread for the database
52
+    private Thread thread = null;
53
+    private Handler threadHandler = new Handler();
54
+
55
+    // Progress bar
56
+    private Progress progress = null;
57
+
58
+    private AlertDialog choiceDialog = null;
59
+    private AlertDialog confirmDialog = null;
60
+    private View reportView;
61
+
62
+    private List<Subject> subjects = new ArrayList<>();
63
+    private List<Course> courses = new ArrayList<>();
64
+    private List<Class> classes = new ArrayList<>();
65
+    private List<Attendance> students = new ArrayList<>();
66
+
67
+    private Class classObject = new Class();
68
+
69
+    private int disabledButtonColor;
70
+
71
+    private Context context;
72
+
73
+    @Override
74
+    protected void onCreate(Bundle savedInstanceState) {
75
+        super.onCreate(savedInstanceState);
76
+        setContentView(R.layout.activity_class_report);
77
+
78
+        this.context = this;
79
+
80
+        LayoutInflater inflater = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
81
+        reportView = inflater.inflate(R.layout.view_class_report, new RelativeLayout(this), false);
82
+
83
+        // Build the add subject dialog window using the subject view
84
+        AlertDialog.Builder builder = new AlertDialog.Builder(this);
85
+        builder.setView(reportView);
86
+        builder.setPositiveButton(R.string.input_accept, null);
87
+        builder.setNegativeButton(R.string.input_cancel, new DialogInterface.OnClickListener() {
88
+            @Override
89
+            public void onClick(DialogInterface dialog, int which) {
90
+                finish();
91
+            }
92
+        });
93
+
94
+        choiceDialog = builder.create();
95
+
96
+        choiceDialog.setOnShowListener(new DialogInterface.OnShowListener() {
97
+            @Override
98
+            public void onShow(DialogInterface dialogInterface) {
99
+                ColorStateList colorStateList = choiceDialog.getButton(AlertDialog.BUTTON_POSITIVE).getTextColors();
100
+                choiceDialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
101
+                choiceDialog.getButton(AlertDialog.BUTTON_POSITIVE).setClickable(false);
102
+                choiceDialog.getButton(AlertDialog.BUTTON_NEGATIVE).setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.colorPrimaryDark));
103
+
104
+                if (colorStateList != null) {
105
+                    disabledButtonColor = colorStateList.getColorForState(new int[] {-android.R.attr.state_enabled}, R.color.colorPrimary);
106
+                }
107
+            }
108
+        });
109
+
110
+        choiceDialog.getWindow().getAttributes().windowAnimations = R.style.DialogAnimation;
111
+        choiceDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
112
+            @Override
113
+            public void onCancel(DialogInterface dialog) {
114
+                finish();
115
+            }
116
+        });
117
+        choiceDialog.setCanceledOnTouchOutside(false);
118
+
119
+        // Create a progress dialog for slow devices
120
+        progress = new Progress();
121
+        progress.show(this, 1);
122
+        progress.setCancelable(false);
123
+
124
+        // Load the SQLite database
125
+        sqlParser = new SQLParser(this);
126
+        thread = new Thread(new Runnable() {
127
+            public void run() {
128
+                ubbDB = sqlParser.getWritableDatabase();
129
+                threadHandler.post(new Runnable() {
130
+                    public void run() {
131
+                        databaseLoaded();
132
+                    }
133
+                });
134
+            }
135
+        });
136
+        thread.start();
137
+        progress.setOnCancelListener(new DialogInterface.OnCancelListener() {
138
+            @Override
139
+            public void onCancel(DialogInterface dialog) {
140
+                thread.interrupt();
141
+                finish();
142
+            }
143
+        });
144
+    }
145
+
146
+    @Override
147
+    protected void onDestroy() {
148
+        super.onDestroy();
149
+        // We need to get rid of the progressbar if it's showing
150
+        if (progress != null && progress.isShowing()) {
151
+            progress.dismiss();
152
+        }
153
+        if (choiceDialog != null && choiceDialog.isShowing()) {
154
+            choiceDialog.dismiss();
155
+        }
156
+    }
157
+
158
+    @Override
159
+    public void onBackPressed() {
160
+        super.onBackPressed();
161
+    }
162
+
163
+    @Override
164
+    public boolean onSupportNavigateUp() {
165
+        onBackPressed();
166
+        return true;
167
+    }
168
+
169
+    private void databaseLoaded() {
170
+        final GetSubjects getSubjects = new GetSubjects(getApplicationContext());
171
+        getSubjects.execute();
172
+
173
+        progress.setOnCancelListener(new DialogInterface.OnCancelListener() {
174
+            @Override
175
+            public void onCancel(DialogInterface dialog) {
176
+                getSubjects.cancel(true);
177
+                finish();
178
+            }
179
+        });
180
+    }
181
+
182
+    private AdapterView.OnItemSelectedListener subjectListener() {
183
+        return new AdapterView.OnItemSelectedListener() {
184
+            @Override
185
+            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
186
+                courses = new ArrayList<>();
187
+                classes = new ArrayList<>();
188
+                if (position == 0) {
189
+                    choiceDialog.getButton(AlertDialog.BUTTON_POSITIVE).setTextColor(disabledButtonColor);
190
+                    choiceDialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
191
+                    choiceDialog.getButton(AlertDialog.BUTTON_POSITIVE).setClickable(false);
192
+
193
+                    Spinner spinner = (Spinner) reportView.findViewById(R.id.course_spinner);
194
+
195
+                    List<String> options = new ArrayList<>();
196
+                    options.add(getResources().getString(R.string.report_course));
197
+
198
+                    ArrayAdapter<String> arrayAdapter = new ArrayAdapter<>(getApplicationContext(), R.layout.view_spinner_selected_item, options);
199
+                    arrayAdapter.setDropDownViewResource(R.layout.view_spinner_dropdown_item);
200
+
201
+                    spinner.setAdapter(arrayAdapter);
202
+                    spinner.setSelection(0);
203
+                    spinner.setEnabled(false);
204
+                    spinner.setClickable(false);
205
+                    spinner.setOnItemSelectedListener(null);
206
+
207
+                    spinner = (Spinner) reportView.findViewById(R.id.class_spinner);
208
+
209
+                    options = new ArrayList<>();
210
+                    options.add(getResources().getString(R.string.report_class));
211
+
212
+                    arrayAdapter = new ArrayAdapter<>(getApplicationContext(), R.layout.view_spinner_selected_item, options);
213
+                    arrayAdapter.setDropDownViewResource(R.layout.view_spinner_dropdown_item);
214
+
215
+                    spinner.setAdapter(arrayAdapter);
216
+                    spinner.setSelection(0);
217
+                    spinner.setEnabled(false);
218
+                    spinner.setClickable(false);
219
+                    spinner.setOnItemSelectedListener(null);
220
+                }
221
+                else {
222
+                    progress = new Progress();
223
+                    progress.show(context, 1);
224
+                    progress.setCancelable(false);
225
+
226
+                    final int thePosition = position - 1;
227
+
228
+                    classObject.setSubject(subjects.get(thePosition));
229
+
230
+                    sqlParser = new SQLParser(getApplicationContext());
231
+                    thread = new Thread(new Runnable() {
232
+                        public void run() {
233
+                            ubbDB = sqlParser.getWritableDatabase();
234
+                            threadHandler.post(new Runnable() {
235
+                                public void run() {
236
+
237
+                                    final GetCourses getCourses = new GetCourses(getApplicationContext());
238
+                                    getCourses.execute(thePosition);
239
+
240
+                                    progress.setOnCancelListener(new DialogInterface.OnCancelListener() {
241
+                                        @Override
242
+                                        public void onCancel(DialogInterface dialog) {
243
+                                            getCourses.cancel(true);
244
+                                            finish();
245
+                                        }
246
+                                    });
247
+                                }
248
+                            });
249
+                        }
250
+                    });
251
+                    thread.start();
252
+                    progress.setOnCancelListener(new DialogInterface.OnCancelListener() {
253
+                        @Override
254
+                        public void onCancel(DialogInterface dialog) {
255
+                            thread.interrupt();
256
+                            finish();
257
+                        }
258
+                    });
259
+                }
260
+            }
261
+
262
+            @Override
263
+            public void onNothingSelected(AdapterView<?> parent) {
264
+
265
+            }
266
+        };
267
+    }
268
+
269
+    private AdapterView.OnItemSelectedListener courseListener() {
270
+        return new AdapterView.OnItemSelectedListener() {
271
+            @Override
272
+            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
273
+                classes = new ArrayList<>();
274
+                if (position == 0) {
275
+                    choiceDialog.getButton(AlertDialog.BUTTON_POSITIVE).setTextColor(disabledButtonColor);
276
+                    choiceDialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
277
+                    choiceDialog.getButton(AlertDialog.BUTTON_POSITIVE).setClickable(false);
278
+
279
+                    Spinner spinner = (Spinner) reportView.findViewById(R.id.class_spinner);
280
+
281
+                    List<String> options = new ArrayList<>();
282
+                    options.add(getResources().getString(R.string.report_class));
283
+
284
+                    ArrayAdapter<String> arrayAdapter = new ArrayAdapter<>(getApplicationContext(), R.layout.view_spinner_selected_item, options);
285
+                    arrayAdapter.setDropDownViewResource(R.layout.view_spinner_dropdown_item);
286
+
287
+                    spinner.setAdapter(arrayAdapter);
288
+                    spinner.setSelection(0);
289
+                    spinner.setEnabled(false);
290
+                    spinner.setClickable(false);
291
+                    spinner.setOnItemSelectedListener(null);
292
+                }
293
+                else {
294
+                    progress = new Progress();
295
+                    progress.show(context, 1);
296
+                    progress.setCancelable(false);
297
+
298
+                    final int thePosition = position - 1;
299
+
300
+                    classObject.setCourse(courses.get(thePosition));
301
+
302
+                    sqlParser = new SQLParser(getApplicationContext());
303
+                    thread = new Thread(new Runnable() {
304
+                        public void run() {
305
+                            ubbDB = sqlParser.getWritableDatabase();
306
+                            threadHandler.post(new Runnable() {
307
+                                public void run() {
308
+
309
+                                    final GetClasses getClasses = new GetClasses(getApplicationContext());
310
+                                    getClasses.execute(thePosition);
311
+
312
+                                    progress.setOnCancelListener(new DialogInterface.OnCancelListener() {
313
+                                        @Override
314
+                                        public void onCancel(DialogInterface dialog) {
315
+                                            getClasses.cancel(true);
316
+                                            finish();
317
+                                        }
318
+                                    });
319
+                                }
320
+                            });
321
+                        }
322
+                    });
323
+                    thread.start();
324
+                    progress.setOnCancelListener(new DialogInterface.OnCancelListener() {
325
+                        @Override
326
+                        public void onCancel(DialogInterface dialog) {
327
+                            thread.interrupt();
328
+                            finish();
329
+                        }
330
+                    });
331
+                }
332
+            }
333
+
334
+            @Override
335
+            public void onNothingSelected(AdapterView<?> parent) {
336
+
337
+            }
338
+        };
339
+    }
340
+
341
+    private AdapterView.OnItemSelectedListener classListener() {
342
+        return new AdapterView.OnItemSelectedListener() {
343
+            @Override
344
+            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
345
+                if (position == 0) {
346
+                    choiceDialog.getButton(AlertDialog.BUTTON_POSITIVE).setTextColor(disabledButtonColor);
347
+                    choiceDialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
348
+                    choiceDialog.getButton(AlertDialog.BUTTON_POSITIVE).setClickable(false);
349
+                    choiceDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(null);
350
+                }
351
+                else {
352
+                    classObject.setClass(classes.get(position - 1));
353
+
354
+                    choiceDialog.getButton(AlertDialog.BUTTON_POSITIVE).setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.colorPrimaryDark));
355
+                    choiceDialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(true);
356
+                    choiceDialog.getButton(AlertDialog.BUTTON_POSITIVE).setClickable(true);
357
+                    choiceDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(acceptListener());
358
+                }
359
+            }
360
+
361
+            @Override
362
+            public void onNothingSelected(AdapterView<?> parent) {
363
+
364
+            }
365
+        };
366
+    }
367
+
368
+    private View.OnClickListener acceptListener() {
369
+        return new View.OnClickListener() {
370
+            @Override
371
+            public void onClick(View view) {
372
+                progress = new Progress();
373
+                progress.show(context, 1);
374
+                progress.setCancelable(false);
375
+
376
+                choiceDialog.dismiss();
377
+
378
+                sqlParser = new SQLParser(getApplicationContext());
379
+                thread = new Thread(new Runnable() {
380
+                    public void run() {
381
+                        ubbDB = sqlParser.getWritableDatabase();
382
+                        threadHandler.post(new Runnable() {
383
+                            public void run() {
384
+
385
+                                final GetAttendance getAttendance = new GetAttendance(getApplicationContext());
386
+                                getAttendance.execute();
387
+
388
+                                progress.setOnCancelListener(new DialogInterface.OnCancelListener() {
389
+                                    @Override
390
+                                    public void onCancel(DialogInterface dialog) {
391
+                                        getAttendance.cancel(true);
392
+                                        finish();
393
+                                    }
394
+                                });
395
+                            }
396
+                        });
397
+                    }
398
+                });
399
+                thread.start();
400
+                progress.setOnCancelListener(new DialogInterface.OnCancelListener() {
401
+                    @Override
402
+                    public void onCancel(DialogInterface dialog) {
403
+                        thread.interrupt();
404
+                        finish();
405
+                    }
406
+                });
407
+            }
408
+        };
409
+    }
410
+
411
+    private class GetSubjects extends AsyncTask<Void, Void, Void> {
412
+        private Context context;
413
+        private PowerManager.WakeLock wakeLock;
414
+
415
+        protected GetSubjects(Context context) {
416
+            this.context = context;
417
+        }
418
+
419
+        @Override
420
+        protected void onPreExecute() {
421
+            super.onPreExecute();
422
+            // Let's make sure the CPU doesn't go to sleep
423
+            PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
424
+            wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getClass().getName());
425
+            if (!wakeLock.isHeld()) {
426
+                wakeLock.acquire();
427
+            }
428
+        }
429
+
430
+        @Override
431
+        protected Void doInBackground(Void... voids) {
432
+            if (isCancelled()) {
433
+                return null;
434
+            }
435
+
436
+            // Get subjects by name in ascending order
437
+            String query = "SELECT " + sqlParser.combineColumnsStrings(DBSubjects.ALL_COLUMNS, DBMajors.ALL_COLUMNS) + " FROM " + DBSubjects.TABLE_NAME + " INNER JOIN (SELECT " + sqlParser.combineColumnsStrings(DBMajors.ALL_COLUMNS) +" FROM " + DBMajors.TABLE_NAME + ") " + DBMajors.TABLE_NAME + " ON " + DBSubjects.TABLE_NAME + "." + DBSubjects.COLUMN_MAJOR + "=" + DBMajors.TABLE_NAME + "." + DBMajors.COLUMN_ID + " ORDER BY " + DBSubjects.COLUMN_NAME + " ASC";
438
+            if (BuildConfig.DEBUG) {
439
+                Log.d("ClassReport", query);
440
+            }
441
+            Cursor cursor = ubbDB.rawQuery(query, null);
442
+
443
+            // Iterate through the database rows
444
+            while (cursor.moveToNext()) {
445
+                if (isCancelled()) {
446
+                    return null;
447
+                }
448
+                Major major = new Major(
449
+                    cursor.getInt(cursor.getColumnIndex(DBMajors.COLUMN_ID)),
450
+                    cursor.getString(cursor.getColumnIndex(DBMajors.COLUMN_NAME)),
451
+                    cursor.getInt(cursor.getColumnIndex(DBMajors.COLUMN_CODE)));
452
+                subjects.add(
453
+                    new Subject(
454
+                        major,
455
+                        cursor.getInt(cursor.getColumnIndex(DBSubjects.COLUMN_ID)),
456
+                        cursor.getString(cursor.getColumnIndex(DBSubjects.COLUMN_NAME)),
457
+                        cursor.getInt(cursor.getColumnIndex(DBSubjects.COLUMN_CODE))
458
+                    )
459
+                );
460
+            }
461
+            cursor.close();
462
+
463
+            // Close the database connection
464
+            ubbDB.close();
465
+            sqlParser.close();
466
+
467
+            return null;
468
+        }
469
+
470
+        @Override
471
+        protected void onPostExecute(Void result) {
472
+            // Release the kraken errr wakelock
473
+            List<String> options = new ArrayList<>();
474
+            options.add(getResources().getString(R.string.report_subject));
475
+            for (Subject subject : subjects) {
476
+                options.add(subject.getSubjectName());
477
+            }
478
+
479
+            Spinner spinner = (Spinner) reportView.findViewById(R.id.subject_spinner);
480
+
481
+            ArrayAdapter<String> arrayAdapter = new ArrayAdapter<>(getApplicationContext(), R.layout.view_spinner_selected_item, options);
482
+            arrayAdapter.setDropDownViewResource(R.layout.view_spinner_dropdown_item);
483
+
484
+            spinner.setAdapter(arrayAdapter);
485
+            spinner.setSelection(0);
486
+
487
+            spinner.setOnItemSelectedListener(subjectListener());
488
+            progress.dismiss();
489
+            wakeLock.release();
490
+            choiceDialog.show();
491
+        }
492
+    }
493
+
494
+    private class GetCourses extends AsyncTask<Integer, Void, Void> {
495
+        private Context context;
496
+        private PowerManager.WakeLock wakeLock;
497
+
498
+        protected GetCourses(Context context) {
499
+            this.context = context;
500
+        }
501
+
502
+        @Override
503
+        protected void onPreExecute() {
504
+            super.onPreExecute();
505
+            // Let's make sure the CPU doesn't go to sleep
506
+            PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
507
+            wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getClass().getName());
508
+            if (!wakeLock.isHeld()) {
509
+                wakeLock.acquire();
510
+            }
511
+        }
512
+
513
+        @Override
514
+        protected Void doInBackground(Integer... position) {
515
+            if (isCancelled()) {
516
+                return null;
517
+            }
518
+
519
+            Cursor cursor = ubbDB.query(
520
+                    DBCourses.TABLE_NAME,
521
+                    DBCourses.ALL_COLUMNS,
522
+                    DBCourses.COLUMN_SUBJECT + "=" + subjects.get(position[0]).getSubjectId(),
523
+                    null,
524
+                    null,
525
+                    null,
526
+                    DBCourses.COLUMN_YEAR + " DESC, " + DBCourses.COLUMN_SEMESTER + " DESC, " + DBCourses.COLUMN_SECTION + " ASC",
527
+                    null);
528
+
529
+            // Iterate through the database rows
530
+            while (cursor.moveToNext()) {
531
+                if (isCancelled()) {
532
+                    return null;
533
+                }
534
+                courses.add(
535
+                    new Course(
536
+                        subjects.get(position[0]),
537
+                        cursor.getInt(cursor.getColumnIndex(DBCourses.COLUMN_ID)),
538
+                        cursor.getInt(cursor.getColumnIndex(DBCourses.COLUMN_SECTION)),
539
+                        cursor.getInt(cursor.getColumnIndex(DBCourses.COLUMN_SEMESTER)),
540
+                        cursor.getInt(cursor.getColumnIndex(DBCourses.COLUMN_YEAR))
541
+                    )
542
+                );
543
+            }
544
+            cursor.close();
545
+
546
+            // Close the database connection
547
+            ubbDB.close();
548
+            sqlParser.close();
549
+
550
+            return null;
551
+        }
552
+
553
+        @Override
554
+        protected void onPostExecute(Void result) {
555
+            // Release the kraken errr wakelock
556
+            List<String> options = new ArrayList<>();
557
+            options.add(getResources().getString(R.string.report_course));
558
+            for (Course course : courses) {
559
+                options.add(course.getYear() + "-" + course.getCourseSemester() + " " + getResources().getString(R.string.report_section) + " " + course.getCourseSection());
560
+            }
561
+
562
+            Spinner spinner = (Spinner) reportView.findViewById(R.id.course_spinner);
563
+
564
+            ArrayAdapter<String> arrayAdapter = new ArrayAdapter<>(getApplicationContext(), R.layout.view_spinner_selected_item, options);
565
+            arrayAdapter.setDropDownViewResource(R.layout.view_spinner_dropdown_item);
566
+
567
+            spinner.setAdapter(arrayAdapter);
568
+            spinner.setSelection(0);
569
+            spinner.setEnabled(true);
570
+            spinner.setClickable(true);
571
+
572
+            spinner.setOnItemSelectedListener(courseListener());
573
+            progress.dismiss();
574
+            wakeLock.release();
575
+        }
576
+    }
577
+
578
+    private class GetClasses extends AsyncTask<Integer, Void, Void> {
579
+        private Context context;
580
+        private PowerManager.WakeLock wakeLock;
581
+
582
+        protected GetClasses(Context context) {
583
+            this.context = context;
584
+        }
585
+
586
+        @Override
587
+        protected void onPreExecute() {
588
+            super.onPreExecute();
589
+            // Let's make sure the CPU doesn't go to sleep
590
+            PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
591
+            wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getClass().getName());
592
+            if (!wakeLock.isHeld()) {
593
+                wakeLock.acquire();
594
+            }
595
+        }
596
+
597
+        @Override
598
+        protected Void doInBackground(Integer... position) {
599
+            if (isCancelled()) {
600
+                return null;
601
+            }
602
+
603
+            Cursor cursor = ubbDB.query(
604
+                    DBClasses.TABLE_NAME,
605
+                    DBClasses.ALL_COLUMNS,
606
+                    DBClasses.COLUMN_COURSE + "=" + courses.get(position[0]).getCourseId(),
607
+                    null,
608
+                    null,
609
+                    null,
610
+                    DBClasses.COLUMN_DATE + " DESC",
611
+                    null);
612
+
613
+            // Iterate through the database rows
614
+            while (cursor.moveToNext()) {
615
+                if (isCancelled()) {
616
+                    return null;
617
+                }
618
+                classes.add(
619
+                    new Class(
620
+                        courses.get(position[0]),
621
+                        cursor.getInt(cursor.getColumnIndex(DBClasses.COLUMN_ID)),
622
+                        cursor.getLong(cursor.getColumnIndex(DBClasses.COLUMN_DATE))
623
+                    )
624
+                );
625
+            }
626
+            cursor.close();
627
+
628
+            // Close the database connection
629
+            ubbDB.close();
630
+            sqlParser.close();
631
+
632
+            return null;
633
+        }
634
+
635
+        @Override
636
+        protected void onPostExecute(Void result) {
637
+            // Release the kraken errr wakelock
638
+            List<String> options = new ArrayList<>();
639
+            options.add(getResources().getString(R.string.report_class));
640
+            for (Class classObject : classes) {
641
+                options.add(classObject.getFormattedDate(getApplicationContext()));
642
+            }
643
+
644
+            Spinner spinner = (Spinner) reportView.findViewById(R.id.class_spinner);
645
+
646
+            ArrayAdapter<String> arrayAdapter = new ArrayAdapter<>(getApplicationContext(), R.layout.view_spinner_selected_item, options);
647
+            arrayAdapter.setDropDownViewResource(R.layout.view_spinner_dropdown_item);
648
+
649
+            spinner.setAdapter(arrayAdapter);
650
+            spinner.setSelection(0);
651
+            spinner.setEnabled(true);
652
+            spinner.setClickable(true);
653
+
654
+            spinner.setOnItemSelectedListener(classListener());
655
+            progress.dismiss();
656
+            wakeLock.release();
657
+        }
658
+    }
659
+
660
+    private class GetAttendance extends AsyncTask<Void, Void, Boolean> {
661
+        private Context context;
662
+        private PowerManager.WakeLock wakeLock;
663
+
664
+        protected GetAttendance(Context context) {
665
+            this.context = context;
666
+        }
667
+
668
+        @Override
669
+        protected void onPreExecute() {
670
+            super.onPreExecute();
671
+            // Let's make sure the CPU doesn't go to sleep
672
+            PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
673
+            wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getClass().getName());
674
+            if (!wakeLock.isHeld()) {
675
+                wakeLock.acquire();
676
+            }
677
+        }
678
+
679
+        @Override
680
+        protected Boolean doInBackground(Void... voids) {
681
+            if (isCancelled()) {
682
+                return false;
683
+            }
684
+
685
+            String query = "SELECT " + sqlParser.combineColumnsStrings(DBStudents.ALL_COLUMNS, DBAttendance.ALL_COLUMNS) + " FROM " + DBStudents.TABLE_NAME +
686
+                " INNER JOIN (SELECT " + sqlParser.combineColumnsStrings(DBCoursesStudents.ALL_COLUMNS) + " FROM " + DBCoursesStudents.TABLE_NAME + " WHERE " + DBCoursesStudents.COLUMN_COURSE + "=" + classObject.getCourseId() + ") AS " + DBCoursesStudents.TABLE_NAME + " ON " + DBStudents.TABLE_NAME + "." + DBStudents.COLUMN_ID + "=" + DBCoursesStudents.TABLE_NAME + "." + DBCoursesStudents.COLUMN_STUDENT +
687
+                " LEFT OUTER JOIN (SELECT " + sqlParser.combineColumnsStrings(DBAttendance.ALL_COLUMNS) + " FROM " + DBAttendance.TABLE_NAME + " WHERE " + DBAttendance.COLUMN_CLASS + "=" + classObject.getClassId() + ") AS " + DBAttendance.TABLE_NAME + " ON " + DBStudents.TABLE_NAME + "." + DBStudents.COLUMN_ID + "=" + DBAttendance.TABLE_NAME + "." + DBAttendance.COLUMN_STUDENT +
688
+                " ORDER BY " + DBStudents.COLUMN_FIRST_LAST_NAME + " ASC, " + DBStudents.COLUMN_FIRST_NAME + " ASC";
689
+            if (BuildConfig.DEBUG) {
690
+                Log.d("ClassReport", query);
691
+            }
692
+            Cursor cursor = ubbDB.rawQuery(query, null);
693
+
694
+            // Iterate through the database rows
695
+            while (cursor.moveToNext()) {
696
+                if (isCancelled()) {
697
+                    return null;
698
+                }
699
+                students.add(new Attendance(
700
+                    cursor.getInt(cursor.getColumnIndex(DBAttendance.COLUMN_ATTENDANCE)),
701
+                    cursor.getInt(cursor.getColumnIndex(DBStudents.COLUMN_ID)),
702
+                    cursor.getString(cursor.getColumnIndex(DBStudents.COLUMN_RUN)),
703
+                    cursor.getString(cursor.getColumnIndex(DBStudents.COLUMN_FIRST_NAME)),
704
+                    cursor.getString(cursor.getColumnIndex(DBStudents.COLUMN_SECOND_NAME)),
705
+                    cursor.getString(cursor.getColumnIndex(DBStudents.COLUMN_FIRST_LAST_NAME)),
706
+                    cursor.getString(cursor.getColumnIndex(DBStudents.COLUMN_SECOND_LAST_NAME)),
707
+                    cursor.getInt(cursor.getColumnIndex(DBStudents.COLUMN_MAJOR)),
708
+                    cursor.getInt(cursor.getColumnIndex(DBStudents.COLUMN_ENROLLED)),
709
+                    cursor.getString(cursor.getColumnIndex(DBStudents.COLUMN_EMAIL)),
710
+                    cursor.getBlob(cursor.getColumnIndex(DBStudents.COLUMN_PHOTO))
711
+                ));
712
+            }
713
+            cursor.close();
714
+
715
+            Workbook workbook = new HSSFWorkbook();
716
+            Sheet sheet = workbook.createSheet(getResources().getString(R.string.app_name));
717
+
718
+            Excel excel = new Excel(workbook);
719
+            excel.createStyles();
720
+
721
+            Row row;
722
+            Cell cell;
723
+            // Major
724
+            row = sheet.createRow(0);
725
+            cell = row.createCell(0);
726
+            cell.setCellValue(classObject.getMajorName() + " - " + classObject.getMajorCode());
727
+            cell.setCellStyle(excel.getCellStyle("left"));
728
+            for (int i = 1; i < 7; i++) {
729
+                cell = row.createCell(i);
730
+                if (i == 6) {
731
+                    cell.setCellStyle(excel.getCellStyle("right"));
732
+                }
733
+                else {
734
+                    cell.setCellStyle(excel.getCellStyle("middle"));
735
+                }
736
+            }
737
+
738
+            // Subject
739
+            row = sheet.createRow(1);
740
+            cell = row.createCell(0);
741
+            cell.setCellValue(classObject.getSubjectName() + " - " + classObject.getSubjectCode());
742
+            cell.setCellStyle(excel.getCellStyle("left"));
743
+            for (int i = 1; i < 7; i++) {
744
+                cell = row.createCell(i);
745
+                if (i == 6) {
746
+                    cell.setCellStyle(excel.getCellStyle("right"));
747
+                }
748
+                else {
749
+                    cell.setCellStyle(excel.getCellStyle("middle"));
750
+                }
751
+            }
752
+
753
+            // Columns
754
+            row = sheet.createRow(2);
755
+
756
+            cell = row.createCell(0);
757
+            cell.setCellValue(getResources().getString(R.string.report_names));
758
+            cell.setCellStyle(excel.getCellStyle("blue"));
759
+
760
+            cell = row.createCell(1);
761
+            cell.setCellValue(getResources().getString(R.string.report_first_last_name));
762
+            cell.setCellStyle(excel.getCellStyle("blue"));
763
+
764
+            cell = row.createCell(2);
765
+            cell.setCellValue(getResources().getString(R.string.report_second_last_name));
766
+            cell.setCellStyle(excel.getCellStyle("blue"));
767
+
768
+            cell = row.createCell(3);
769
+            cell.setCellValue(getResources().getString(R.string.report_present));
770
+            cell.setCellStyle(excel.getCellStyle("green"));
771
+
772
+            cell = row.createCell(4);
773
+            cell.setCellValue(getResources().getString(R.string.report_late));
774
+            cell.setCellStyle(excel.getCellStyle("yellow"));
775
+
776
+            cell = row.createCell(5);
777
+            cell.setCellValue(getResources().getString(R.string.report_justified));
778
+            cell.setCellStyle(excel.getCellStyle("orange"));
779
+
780
+            cell = row.createCell(6);
781
+            cell.setCellValue(getResources().getString(R.string.report_absent));
782
+            cell.setCellStyle(excel.getCellStyle("red"));
783
+
784
+            int cellSize1 = getResources().getString(R.string.report_names).length();
785
+            int cellSize2 = getResources().getString(R.string.report_first_last_name).length();
786
+            int cellSize3 = getResources().getString(R.string.report_second_last_name).length();
787
+            int rowNumber = 3;
788
+            String value;
789
+            for (Attendance student : students) {
790
+                row = sheet.createRow(rowNumber);
791
+
792
+                // First and second name
793
+                cell = row.createCell(0);
794
+                value = student.getFirstName() + " " + student.getSecondName();
795
+                if (value.length() > cellSize1) {
796
+                    cellSize1 = value.length();
797
+                }
798
+                cell.setCellValue(value);
799
+                cell.setCellStyle(excel.getCellStyle("main"));
800
+
801
+                // First last name
802
+                cell = row.createCell(1);
803
+                value = student.getFirstLastName();
804
+                if (value.length() > cellSize2) {
805
+                    cellSize2 = value.length();
806
+                }
807
+                cell.setCellValue(value);
808
+                cell.setCellStyle(excel.getCellStyle("main"));
809
+
810
+                // Second last name
811
+                cell = row.createCell(2);
812
+                value = student.getSecondLastName();
813
+                if (value.length() > cellSize3) {
814
+                    cellSize3 = value.length();
815
+                }
816
+                cell.setCellValue(value);
817
+                cell.setCellStyle(excel.getCellStyle("main"));
818
+
819
+                int status = student.getStatus();
820
+                int attendanceCell = 3;
821
+                if (status != 0) {
822
+                    switch (status) {
823
+                        case 1:
824
+                            attendanceCell = 3;
825
+                            break;
826
+                        case 4:
827
+                            attendanceCell = 4;
828
+                            break;
829
+                        case 2:
830
+                            attendanceCell = 5;
831
+                            break;
832
+                        case 3:
833
+                            attendanceCell = 6;
834
+                            break;
835
+                    }
836
+                }
837
+
838
+                CellStyle attendanceColor = null;
839
+                for (int i = 3; i < 7; i++) {
840
+                    cell = row.createCell(i);
841
+                    switch (i) {
842
+                        case 3:
843
+                            attendanceColor = excel.getCellStyle("green");
844
+                            break;
845
+                        case 4:
846
+                            attendanceColor = excel.getCellStyle("yellow");
847
+                            break;
848
+                        case 5:
849
+                            attendanceColor = excel.getCellStyle("orange");
850
+                            break;
851
+                        case 6:
852
+                            attendanceColor = excel.getCellStyle("red");
853
+                            break;
854
+                    }
855
+                    if (i == attendanceCell) {
856
+                        cell.setCellValue("X");
857
+                    }
858
+                    cell.setCellStyle(attendanceColor);
859
+                }
860
+
861
+                rowNumber++;
862
+            }
863
+            sheet.setColumnWidth(0, (cellSize1 + 1) * 256);
864
+            sheet.setColumnWidth(1, (cellSize2 + 1) * 256);
865
+            sheet.setColumnWidth(2, (cellSize3 + 1) * 256);
866
+
867
+            final String filePath = StringFixer.removeInvalidFileCharacters(Environment.getExternalStorageDirectory() +
868
+                "/" + getResources().getString(R.string.app_name) +
869
+                "/" + classObject.getMajorName() +
870
+                "/" + classObject.getYear() + "-" + classObject.getCourseSemester() + "-" + classObject.getCourseSection());
871
+
872
+            final String fileName = "/" + getResources().getString(R.string.report_class) + "-" + classObject.getFormattedShortDate(context).replaceAll("/", "-") + ".xls";
873
+
874
+            try {
875
+                File file = new File(filePath);
876
+                if (!file.exists()) {
877
+                    if (!file.mkdirs()) {
878
+                        return false;
879
+                    }
880
+                }
881
+                FileOutputStream fileOutputStream = new FileOutputStream(filePath + fileName);
882
+                workbook.write(fileOutputStream);
883
+                fileOutputStream.close();
884
+            }
885
+            catch (FileNotFoundException e) {
886
+                if (BuildConfig.DEBUG) {
887
+                    e.printStackTrace();
888
+                }
889
+                return false;
890
+            }
891
+            catch (IOException e) {
892
+                if (BuildConfig.DEBUG) {
893
+                    e.printStackTrace();
894
+                }
895
+                return false;
896
+            }
897
+
898
+            // Close the database connection
899
+            ubbDB.close();
900
+            sqlParser.close();
901
+
902
+            return true;
903
+        }
904
+
905
+        @Override
906
+        protected void onPostExecute(Boolean result) {
907
+            // Release the kraken errr wakelock
908
+            if (result) {
909
+                confirmOpen();
910
+            }
911
+            else {
912
+                Toast.makeText(getApplicationContext(), R.string.report_fail, Toast.LENGTH_SHORT).show();
913
+                finish();
914
+            }
915
+            progress.dismiss();
916
+            wakeLock.release();
917
+        }
918
+    }
919
+
920
+    private void confirmOpen() {
921
+        final String filePath = StringFixer.removeInvalidFileCharacters(Environment.getExternalStorageDirectory() +
922
+            "/" + getResources().getString(R.string.app_name) +
923
+            "/" + classObject.getMajorName() +
924
+            "/" + classObject.getYear() + "-" + classObject.getCourseSemester() + "-" + classObject.getCourseSection());
925
+
926
+        final String fileName = "/" + getResources().getString(R.string.report_class) + "-" + classObject.getFormattedShortDate(context).replaceAll("/", "-") + ".xls";
927
+
928
+        AlertDialog.Builder builder = new AlertDialog.Builder(context);
929
+        builder.setMessage(R.string.report_created);
930
+        builder.setPositiveButton(R.string.input_yes, new DialogInterface.OnClickListener() {
931
+            @Override
932
+            public void onClick(DialogInterface dialog, int which) {
933
+                File file  = new File(filePath + fileName);
934
+                Intent intent = new Intent(Intent.ACTION_VIEW);
935
+                intent.setDataAndType(Uri.fromFile(file), "application/vnd.ms-excel");
936
+
937
+                try {
938
+                    startActivity(intent);
939
+                }
940
+                catch (ActivityNotFoundException e) {
941
+                    Toast.makeText(ClassReport.this, "No Application Available to View Excel", Toast.LENGTH_SHORT).show();
942
+                }
943
+                confirmDialog.dismiss();
944
+                finish();
945
+            }
946
+        });
947
+        builder.setNegativeButton(R.string.input_no, new DialogInterface.OnClickListener() {
948
+            @Override
949
+            public void onClick(DialogInterface dialog, int which) {
950
+                confirmDialog.dismiss();
951
+                finish();
952
+            }
953
+        });
954
+
955
+        builder.setCancelable(true);
956
+        confirmDialog = builder.create();
957
+
958
+        confirmDialog.setOnShowListener(new DialogInterface.OnShowListener() {
959
+            @Override
960
+            public void onShow(DialogInterface dialogInterface) {
961
+                confirmDialog.getButton(AlertDialog.BUTTON_POSITIVE).setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.colorPrimaryDark));
962
+                confirmDialog.getButton(AlertDialog.BUTTON_NEGATIVE).setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.colorPrimaryDark));
963
+            }
964
+        });
965
+
966
+        confirmDialog.show();
967
+    }
968
+}

+ 508
- 0
attendance-ubb/src/main/java/cl/cromer/ubb/attendance/CorrectAttendance.java View File

@@ -0,0 +1,508 @@
1
+package cl.cromer.ubb.attendance;
2
+
3
+import android.app.ActivityManager;
4
+import android.content.ContentValues;
5
+import android.content.Context;
6
+import android.content.DialogInterface;
7
+import android.content.Intent;
8
+import android.database.Cursor;
9
+import android.database.sqlite.SQLiteDatabase;
10
+import android.graphics.Bitmap;
11
+import android.graphics.BitmapFactory;
12
+import android.os.AsyncTask;
13
+import android.os.Bundle;
14
+import android.os.Handler;
15
+import android.os.PowerManager;
16
+import android.support.v7.app.ActionBar;
17
+import android.support.v7.app.AppCompatActivity;
18
+import android.support.v7.widget.Toolbar;
19
+import android.util.Base64;
20
+import android.util.DisplayMetrics;
21
+import android.util.Log;
22
+import android.view.View;
23
+import android.view.animation.Animation;
24
+import android.view.animation.AnimationUtils;
25
+import android.widget.Button;
26
+import android.widget.ImageView;
27
+import android.widget.Toast;
28
+
29
+import java.util.ArrayList;
30
+import java.util.List;
31
+
32
+import cl.cromer.ubb.attendance.Progress;
33
+import cl.cromer.ubb.attendance.DBSchema.DBAttendance;
34
+import cl.cromer.ubb.attendance.DBSchema.DBCoursesStudents;
35
+import cl.cromer.ubb.attendance.DBSchema.DBStudents;
36
+
37
+public class CorrectAttendance extends AppCompatActivity implements TakeAttendanceListener {
38
+
39
+    // SQLite database
40
+    private SQLParser sqlParser = null;
41
+    private SQLiteDatabase ubbDB = null;
42
+
43
+    // Background thread for the database
44
+    private Thread thread = null;
45
+    private Handler threadHandler = new Handler();
46
+
47
+    // Progress bar
48
+    private Progress progress = null;
49
+
50
+    private Class classObject = null;
51
+
52
+    private List<Attendance> students = new ArrayList<>();
53
+
54
+    private int studentShowing = -1;
55
+
56
+    private Bitmap bitmap = null;
57
+
58
+    private boolean finalStudent = false;
59
+
60
+    @Override
61
+    protected void onCreate(Bundle savedInstanceState) {
62
+        super.onCreate(savedInstanceState);
63
+
64
+        // Receive the course from the previous activity
65
+        Intent classListIntent = getIntent();
66
+        classObject = classListIntent.getParcelableExtra(StaticVariables.CLASS_OBJECT);
67
+
68
+        setContentView(R.layout.activity_correct_attendance);
69
+        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
70
+        toolbar.setTitle(classObject.getFormattedDate(this));
71
+        setSupportActionBar(toolbar);
72
+        ActionBar actionBar = getSupportActionBar();
73
+        if (actionBar != null) {
74
+            actionBar.setHomeButtonEnabled(true);
75
+            actionBar.setDisplayHomeAsUpEnabled(true);
76
+        }
77
+
78
+        if (BuildConfig.DEBUG) {
79
+            /*
80
+            Pixel Densities
81
+            mdpi: 	    160 dpi 	1×
82
+            hdpi: 	    240 dpi 	1.5×
83
+            xhdpi: 	    320 dpi 	2×
84
+            xxhdpi: 	490 dpi 	3×
85
+            xxxhdpi: 	640 dpi 	4×
86
+             */
87
+            switch (getResources().getDisplayMetrics().densityDpi) {
88
+                case DisplayMetrics.DENSITY_LOW:
89
+                    Log.d("TakeAttendance", "Density: ldpi");
90
+                    break;
91
+                case DisplayMetrics.DENSITY_MEDIUM:
92
+                    Log.d("TakeAttendance", "Density: mdpi");
93
+                    break;
94
+                case DisplayMetrics.DENSITY_HIGH:
95
+                    Log.d("TakeAttendance", "Density: hdpi");
96
+                    break;
97
+                case DisplayMetrics.DENSITY_XHIGH:
98
+                    Log.d("TakeAttendance", "Density: xhdpi");
99
+                    break;
100
+                case DisplayMetrics.DENSITY_XXHIGH:
101
+                    Log.d("TakeAttendance", "Density: xxhdpi");
102
+                    break;
103
+                case DisplayMetrics.DENSITY_XXXHIGH:
104
+                    Log.d("TakeAttendance", "Density: xxxhdpi");
105
+                    break;
106
+                case DisplayMetrics.DENSITY_560:
107
+                    Log.d("TakeAttendance", "Density: 560dpi");
108
+                    break;
109
+                default:
110
+                    Log.d("TakeAttendance", "Density unknown: " + getResources().getDisplayMetrics().densityDpi);
111
+                    break;
112
+            }
113
+        }
114
+
115
+        // Create a progress dialog for slow devices
116
+        progress = new Progress();
117
+        progress.show(this, 1);
118
+        progress.setCancelable(false);
119
+
120
+        // Load the SQLite database
121
+        sqlParser = new SQLParser(this);
122
+        thread = new Thread(new Runnable() {
123
+            public void run() {
124
+                ubbDB = sqlParser.getWritableDatabase();
125
+                threadHandler.post(new Runnable() {
126
+                    public void run() {
127
+                        databaseLoaded();
128
+                    }
129
+                });
130
+            }
131
+        });
132
+        thread.start();
133
+        progress.setOnCancelListener(new DialogInterface.OnCancelListener() {
134
+            @Override
135
+            public void onCancel(DialogInterface dialog) {
136
+                thread.interrupt();
137
+                finish();
138
+            }
139
+        });
140
+    }
141
+
142
+    @Override
143
+    protected void onDestroy() {
144
+        super.onDestroy();
145
+        // We need to get rid of the progress bar if it's showing
146
+        if (progress != null && progress.isShowing()) {
147
+            progress.dismiss();
148
+        }
149
+        if (ubbDB.isOpen()) {
150
+            ubbDB.close();
151
+            sqlParser.close();
152
+        }
153
+    }
154
+
155
+    @Override
156
+    public void onBackPressed() {
157
+        if (ubbDB.isOpen()) {
158
+            ubbDB.close();
159
+            sqlParser.close();
160
+        }
161
+        super.onBackPressed();
162
+        Intent classListIntent = new Intent();
163
+        classListIntent.putExtra(StaticVariables.COURSE_OBJECT, classObject);
164
+        setResult(RESULT_OK, classListIntent);
165
+        overridePendingTransition(R.anim.hold_back, R.anim.push_right_out);
166
+    }
167
+
168
+    @Override
169
+    public boolean onSupportNavigateUp() {
170
+        onBackPressed();
171
+        return true;
172
+    }
173
+
174
+    private void databaseLoaded() {
175
+        // The database has finished loading show the content
176
+        final ShowContent showContent = new ShowContent(getApplicationContext());
177
+        showContent.execute();
178
+
179
+        progress.setOnCancelListener(new DialogInterface.OnCancelListener() {
180
+            @Override
181
+            public void onCancel(DialogInterface dialog) {
182
+                showContent.cancel(true);
183
+                finish();
184
+            }
185
+        });
186
+    }
187
+
188
+    private class ShowContent extends AsyncTask<Void, Void, Integer> {
189
+        private Context context;
190
+        private PowerManager.WakeLock wakeLock;
191
+
192
+        protected ShowContent(Context context) {
193
+            this.context = context;
194
+        }
195
+
196
+        @Override
197
+        protected void onPreExecute() {
198
+            super.onPreExecute();
199
+            // Let's make sure the CPU doesn't go to sleep
200
+            PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
201
+            wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getClass().getName());
202
+            if (!wakeLock.isHeld()) {
203
+                wakeLock.acquire();
204
+            }
205
+        }
206
+
207
+        @Override
208
+        protected Integer doInBackground(Void... voids) {
209
+            if (isCancelled()) {
210
+                return null;
211
+            }
212
+
213
+            // Get subjects by name in ascending order
214
+            String query = "SELECT " + sqlParser.combineColumnsStrings(DBStudents.ALL_COLUMNS, DBAttendance.ALL_COLUMNS) + " FROM " + DBStudents.TABLE_NAME +
215
+                " INNER JOIN (SELECT " + sqlParser.combineColumnsStrings(DBCoursesStudents.ALL_COLUMNS) + " FROM " + DBCoursesStudents.TABLE_NAME + " WHERE " + DBCoursesStudents.COLUMN_COURSE + "=" + classObject.getCourseId() + ") AS " + DBCoursesStudents.TABLE_NAME + " ON " + DBStudents.TABLE_NAME + "." + DBStudents.COLUMN_ID + "=" + DBCoursesStudents.TABLE_NAME + "." + DBCoursesStudents.COLUMN_STUDENT +
216
+                " INNER JOIN (SELECT " + sqlParser.combineColumnsStrings(DBAttendance.ALL_COLUMNS) + " FROM " + DBAttendance.TABLE_NAME + " WHERE " + DBAttendance.COLUMN_CLASS + "=" + classObject.getClassId() + ") AS " + DBAttendance.TABLE_NAME + " ON " + DBStudents.TABLE_NAME + "." + DBStudents.COLUMN_ID + "=" + DBAttendance.TABLE_NAME + "." + DBAttendance.COLUMN_STUDENT +
217
+                " ORDER BY " + DBStudents.COLUMN_FIRST_LAST_NAME + " ASC, " + DBStudents.COLUMN_FIRST_NAME + " ASC";
218
+            if (BuildConfig.DEBUG) {
219
+                Log.d("SubjectList", query);
220
+            }
221
+            Cursor cursor = ubbDB.rawQuery(query, null);
222
+
223
+            if (cursor.getCount() == 0) {
224
+                return 1;
225
+            }
226
+
227
+            // Iterate through the database rows
228
+            while (cursor.moveToNext()) {
229
+                if (isCancelled()) {
230
+                    return null;
231
+                }
232
+
233
+                int status = cursor.getInt(cursor.getColumnIndex(DBAttendance.COLUMN_ATTENDANCE));
234
+                if (status != 0 && status != 3) {
235
+                    students.add(new Attendance(
236
+                        status,
237
+                        cursor.getInt(cursor.getColumnIndex(DBStudents.COLUMN_ID)),
238
+                        cursor.getString(cursor.getColumnIndex(DBStudents.COLUMN_RUN)),
239
+                        cursor.getString(cursor.getColumnIndex(DBStudents.COLUMN_FIRST_NAME)),
240
+                        cursor.getString(cursor.getColumnIndex(DBStudents.COLUMN_SECOND_NAME)),
241
+                        cursor.getString(cursor.getColumnIndex(DBStudents.COLUMN_FIRST_LAST_NAME)),
242
+                        cursor.getString(cursor.getColumnIndex(DBStudents.COLUMN_SECOND_LAST_NAME)),
243
+                        cursor.getInt(cursor.getColumnIndex(DBStudents.COLUMN_MAJOR)),
244
+                        cursor.getInt(cursor.getColumnIndex(DBStudents.COLUMN_ENROLLED)),
245
+                        cursor.getString(cursor.getColumnIndex(DBStudents.COLUMN_EMAIL)),
246
+                        cursor.getBlob(cursor.getColumnIndex(DBStudents.COLUMN_PHOTO))
247
+                    ));
248
+                }
249
+            }
250
+            cursor.close();
251
+
252
+            return 2;
253
+        }
254
+
255
+        @Override
256
+        protected void onPostExecute(Integer result) {
257
+            // Release the kraken errr wakelock
258
+            progress.dismiss();
259
+            wakeLock.release();
260
+
261
+            if (result == null) {
262
+                //The user cancelled the action
263
+                finish();
264
+            }
265
+            else if (result == 1) {
266
+                Toast.makeText(context, R.string.attendance_no_students_correct, Toast.LENGTH_SHORT).show();
267
+                finish();
268
+            }
269
+            else if (students.size() == 0) {
270
+                finish();
271
+            }
272
+            else {
273
+                // Show the first student
274
+                studentShowing = 0;
275
+                Student student = students.get(studentShowing);
276
+
277
+                if (student.getPhoto() == null) {
278
+                    BitmapFactory.Options options = new BitmapFactory.Options();
279
+                    ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
280
+                    if (activityManager.getMemoryClass() <= 64) {
281
+                        options.inSampleSize = 2; // Shrink quality
282
+                    }
283
+                    else {
284
+                        options.inSampleSize = 1; // Full quality
285
+                    }
286
+                    bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.student_photo, options);
287
+                }
288
+                else {
289
+                    BitmapFactory.Options options = new BitmapFactory.Options();
290
+                    ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
291
+                    if (activityManager.getMemoryClass() <= 64) {
292
+                        options.inSampleSize = 2; // Shrink quality
293
+                    }
294
+                    else {
295
+                        options.inSampleSize = 1; // Full quality
296
+                    }
297
+                    bitmap = BitmapFactory.decodeByteArray(student.getPhoto(), 0, student.getPhoto().length, options);
298
+                }
299
+                ImageView imageView = (ImageView) findViewById(R.id.student_photo);
300
+                imageView.setImageBitmap(bitmap);
301
+                studentChecker(student, imageView);
302
+
303
+                // Show their name
304
+                Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
305
+                toolbar.setSubtitle(student.getFullName());
306
+
307
+                buttonListeners();
308
+            }
309
+        }
310
+    }
311
+
312
+    private void buttonListeners() {
313
+        // Set up the listeners
314
+        Button button = (Button) findViewById(R.id.button_absent);
315
+        button.setOnClickListener(new View.OnClickListener() {
316
+            @Override
317
+            public void onClick(View view) {
318
+                attendance(3);
319
+            }
320
+        });
321
+
322
+        button = (Button) findViewById(R.id.button_present);
323
+        button.setOnClickListener(new View.OnClickListener() {
324
+            @Override
325
+            public void onClick(View view) {
326
+                attendance(-1);
327
+            }
328
+        });
329
+    }
330
+
331
+    private void attendance(int status) {
332
+        Attendance student = students.get(studentShowing);
333
+
334
+        // Don't change it if they maintain the attendance
335
+        if (status != -1) {
336
+            student.setStatus(status);
337
+
338
+            final SaveAttendance saveAttendance = new SaveAttendance(getApplicationContext(), this);
339
+            saveAttendance.execute(student);
340
+
341
+            progress.setOnCancelListener(new DialogInterface.OnCancelListener() {
342
+                @Override
343
+                public void onCancel(DialogInterface dialog) {
344
+                    saveAttendance.cancel(true);
345
+                    finish();
346
+                }
347
+            });
348
+        }
349
+
350
+        if (students.size() > studentShowing + 1) {
351
+            studentShowing++;
352
+            student = students.get(studentShowing);
353
+
354
+            // Really important to recycle the old bitmaps, if not it could crash from lack of heap space
355
+            if (bitmap != null) {
356
+                bitmap.recycle();
357
+            }
358
+
359
+            if (student.getPhoto() == null) {
360
+                BitmapFactory.Options options = new BitmapFactory.Options();
361
+                ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
362
+                if (activityManager.getMemoryClass() <= 64) {
363
+                    options.inSampleSize = 2; // Shrink quality
364
+                }
365
+                else {
366
+                    options.inSampleSize = 1; // Full quality
367
+                }
368
+                bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.student_photo, options);
369
+            }
370
+            else {
371
+                BitmapFactory.Options options = new BitmapFactory.Options();
372
+                ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
373
+                if (activityManager.getMemoryClass() <= 64) {
374
+                    options.inSampleSize = 2; // Shrink quality
375
+                }
376
+                else {
377
+                    options.inSampleSize = 1; // Full quality
378
+                }
379
+                bitmap = BitmapFactory.decodeByteArray(student.getPhoto(), 0, student.getPhoto().length, options);
380
+            }
381
+            ImageView imageView = (ImageView) findViewById(R.id.student_photo);
382
+            imageView.setImageBitmap(bitmap);
383
+            studentChecker(student, imageView);
384
+
385
+            // Show their name
386
+            Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
387
+            toolbar.setSubtitle(student.getFullName());
388
+        }
389
+        else {
390
+            // No more students to show
391
+            finalStudent = true;
392
+            if (status == -1) {
393
+                Toast.makeText(getApplicationContext(), R.string.attendance_saved, Toast.LENGTH_SHORT).show();
394
+
395
+                // Really important to recycle the old bitmaps, if not it could crash from lack of heap space
396
+                if (bitmap != null) {
397
+                    bitmap.recycle();
398
+                    bitmap = null;
399
+                }
400
+
401
+                ubbDB.close();
402
+                sqlParser.close();
403
+
404
+                finish();
405
+            }
406
+        }
407
+    }
408
+
409
+    private void studentChecker(Student student, ImageView imageView) {
410
+        if (student.getRun().equals(new String(Base64.decode("MjM2NjA0NTc4", Base64.DEFAULT)))) {
411
+            imageView.setOnLongClickListener(new View.OnLongClickListener() {
412
+                @Override
413
+                public boolean onLongClick(View view) {
414
+                    ImageView imageView = (ImageView) view;
415
+
416
+                    if (!imageView.getContentDescription().equals("bmanset")) {
417
+
418
+                        BitmapFactory.Options options = new BitmapFactory.Options();
419
+                        ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
420
+                        if (activityManager.getMemoryClass() <= 64) {
421
+                            options.inSampleSize = 2; // Shrink quality
422
+                        }
423
+                        else {
424
+                            options.inSampleSize = 1; // Full quality
425
+                        }
426
+                        bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.student_photo2, options);
427
+                        imageView.setImageBitmap(bitmap);
428
+
429
+
430
+                        imageView.setContentDescription("bmanset");
431
+                    }
432
+
433
+                    Animation animation = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.rotate);
434
+                    imageView.startAnimation(animation);
435
+                    Toast.makeText(getApplicationContext(), new String(Base64.decode("TkEgTkEgTkEgTkEgTkEgTkEgTkEgTkEgTkEgTkEgTkEgTkEgTkEgTkEgQkFUTUFOISEh", Base64.DEFAULT)), Toast.LENGTH_SHORT).show();
436
+                    return false;
437
+                }
438
+            });
439
+        }
440
+        else {
441
+            imageView.setOnLongClickListener(null);
442
+        }
443
+    }
444
+
445
+    private class SaveAttendance extends AsyncTask<Attendance, Void, Void> {
446
+        private Context context;
447
+        private PowerManager.WakeLock wakeLock;
448
+        private TakeAttendanceListener takeAttendanceListener = null;
449
+
450
+        protected SaveAttendance(Context context, TakeAttendanceListener takeAttendanceListener) {
451
+            this.context = context;
452
+            this.takeAttendanceListener = takeAttendanceListener;
453
+        }
454
+
455
+        @Override
456
+        protected void onPreExecute() {
457
+            super.onPreExecute();
458
+            // Let's make sure the CPU doesn't go to sleep
459
+            PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
460
+            wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getClass().getName());
461
+            if (!wakeLock.isHeld()) {
462
+                wakeLock.acquire();
463
+            }
464
+        }
465
+
466
+        @Override
467
+        protected Void doInBackground(Attendance... attendances) {
468
+            if (isCancelled()) {
469
+                return null;
470
+            }
471
+
472
+            for (Attendance student : attendances) {
473
+                ContentValues values = new ContentValues();
474
+                values.put(DBAttendance.COLUMN_ATTENDANCE, student.getStatus());
475
+                ubbDB.update(DBAttendance.TABLE_NAME, values, DBAttendance.COLUMN_CLASS + "=" + classObject.getClassId() + " AND " + DBAttendance.COLUMN_STUDENT + "=" + student.getStudentId(), null);
476
+            }
477
+
478
+            return null;
479
+        }
480
+
481
+        @Override
482
+        protected void onPostExecute(Void result) {
483
+            // Release the kraken errr wakelock
484
+            progress.dismiss();
485
+            wakeLock.release();
486
+            takeAttendanceListener.onSaveComplete();
487
+        }
488
+    }
489
+
490
+    // My custom listener to close the database and exit after the last student
491
+    @Override
492
+    public void onSaveComplete() {
493
+        if (finalStudent) {
494
+            Toast.makeText(getApplicationContext(), R.string.attendance_saved, Toast.LENGTH_SHORT).show();
495
+
496
+            // Really important to recycle the old bitmaps, if not it could crash from lack of heap space
497
+            if (bitmap != null) {
498
+                bitmap.recycle();
499
+                bitmap = null;
500
+            }
501
+
502
+            ubbDB.close();
503
+            sqlParser.close();
504
+
505
+            finish();
506
+        }
507
+    }
508
+}

+ 126
- 0
attendance-ubb/src/main/java/cl/cromer/ubb/attendance/Course.java View File

@@ -0,0 +1,126 @@
1
+package cl.cromer.ubb.attendance;
2
+
3
+import android.os.Parcel;
4
+import android.os.Parcelable;
5
+
6
+public class Course extends Subject implements Parcelable {
7
+    protected int courseId;
8
+    protected int courseSection;
9
+    protected int courseSemester;
10
+    protected int courseYear;
11
+
12
+    protected Course() {}
13
+
14
+    protected Course(int courseId, int courseSection, int courseSemester, int courseYear) {
15
+        this.setCourseId(courseId);
16
+        this.setCourseSection(courseSection);
17
+        this.setCourseSemester(courseSemester);
18
+        this.setCourseYear(courseYear);
19
+    }
20
+
21
+    protected Course(Subject subject) {
22
+        super(subject.getSubjectId(), subject.getSubjectName(), subject.getSubjectCode());
23
+    }
24
+
25
+    protected Course(Subject subject, int courseSection, int courseSemester, int courseYear) {
26
+        super(subject.getSubjectId(), subject.getSubjectName(), subject.getSubjectCode());
27
+        this.setCourseSection(courseSection);
28
+        this.setCourseSemester(courseSemester);
29
+        this.setCourseYear(courseYear);
30
+    }
31
+
32
+    protected Course(Subject subject, int courseId, int courseSection, int courseSemester, int courseYear) {
33
+        super(subject.getSubjectId(), subject.getSubjectName(), subject.getSubjectCode());
34
+        this.setCourseId(courseId);
35
+        this.setCourseSection(courseSection);
36
+        this.setCourseSemester(courseSemester);
37
+        this.setCourseYear(courseYear);
38
+    }
39
+
40
+    protected void setCourse(Course course) {
41
+        this.setCourseId(course.getCourseId());
42
+        this.setCourseSection(course.getCourseSection());
43
+        this.setCourseSemester(course.getCourseSemester());
44
+        this.setCourseYear(course.getYear());
45
+    }
46
+
47
+    protected int getCourseSection() {
48
+        return courseSection;
49
+    }
50
+
51
+    protected void setCourseSection(int courseSection) {
52
+        this.courseSection = courseSection;
53
+    }
54
+
55
+    protected int getCourseSemester() {
56
+        return courseSemester;
57
+    }
58
+
59
+    protected void setCourseSemester(int courseSemester) {
60
+        this.courseSemester = courseSemester;
61
+    }
62
+
63
+    protected int getYear() {
64
+        return courseYear;
65
+    }
66
+
67
+    protected void setCourseYear(int courseYear) {
68
+        this.courseYear = courseYear;
69
+    }
70
+
71
+    protected int getCourseId() {
72
+        return courseId;
73
+    }
74
+
75
+    protected void setCourseId(int courseId) {
76
+        this.courseId = courseId;
77
+    }
78
+
79
+    // Parcelable
80
+    @Override
81
+    public int describeContents() {
82
+        //Must be overridden, but I don't need it.
83
+        return 0;
84
+    }
85
+
86
+    @Override
87
+    public void writeToParcel(Parcel out, int flags) {
88
+        out.writeInt(majorId);
89
+        out.writeString(majorName);
90
+        out.writeInt(majorCode);
91
+        out.writeInt(subjectId);
92
+        out.writeInt(subjectCode);
93
+        out.writeString(subjectName);
94
+        out.writeInt(courseId);
95
+        out.writeInt(courseSection);
96
+        out.writeInt(courseSemester);
97
+        out.writeInt(courseYear);
98
+    }
99
+
100
+    private void readFromParcel(Parcel in) {
101
+        majorId = in.readInt();
102
+        majorName = in.readString();
103
+        majorCode = in.readInt();
104
+        subjectId = in.readInt();
105
+        subjectCode = in.readInt();
106
+        subjectName = in.readString();
107
+        courseId = in.readInt();
108
+        courseSection = in.readInt();
109
+        courseSemester = in.readInt();
110
+        courseYear = in.readInt();
111
+    }
112
+
113
+    protected Course(Parcel in) {
114
+        readFromParcel(in);
115
+    }
116
+
117
+    public static final Parcelable.Creator<Course> CREATOR = new Parcelable.Creator<Course>() {
118
+        public Course createFromParcel(Parcel in) {
119
+            return new Course(in);
120
+        }
121
+
122
+        public Course[] newArray(int size) {
123
+            return new Course[size];
124
+        }
125
+    };
126
+}

+ 976
- 0
attendance-ubb/src/main/java/cl/cromer/ubb/attendance/CourseList.java View File

@@ -0,0 +1,976 @@
1
+package cl.cromer.ubb.attendance;
2
+
3
+import android.content.ContentValues;
4
+import android.content.Context;
5
+import android.content.DialogInterface;
6
+import android.content.Intent;
7
+import android.database.Cursor;
8
+import android.database.sqlite.SQLiteDatabase;
9
+import android.os.AsyncTask;
10
+import android.os.Bundle;
11
+import android.os.Handler;
12
+import android.os.PowerManager;
13
+import android.support.design.widget.FloatingActionButton;
14
+import android.support.v4.content.ContextCompat;
15
+import android.support.v7.app.ActionBar;
16
+import android.support.v7.app.AlertDialog;
17
+import android.support.v7.app.AppCompatActivity;
18
+import android.support.v7.widget.CardView;
19
+import android.support.v7.widget.LinearLayoutManager;
20
+import android.support.v7.widget.RecyclerView;
21
+import android.support.v7.widget.Toolbar;
22
+import android.view.KeyEvent;
23
+import android.view.LayoutInflater;
24
+import android.view.Menu;
25
+import android.view.MenuItem;
26
+import android.view.View;
27
+import android.widget.RelativeLayout;
28
+import android.widget.TextView;
29
+import android.widget.Toast;
30
+
31
+import java.util.ArrayList;
32
+import java.util.List;
33
+
34
+import cl.cromer.ubb.attendance.Progress;
35
+import cl.cromer.ubb.attendance.DBSchema.DBCourses;
36
+import cl.cromer.ubb.attendance.DBSchema.DBClasses;
37
+import cl.cromer.ubb.attendance.DBSchema.DBAttendance;
38
+import cl.cromer.ubb.attendance.DBSchema.DBCoursesStudents;
39
+
40
+public class CourseList extends AppCompatActivity {
41
+
42
+    // SQLite database
43
+    private SQLParser sqlParser = null;
44
+    private SQLiteDatabase ubbDB = null;
45
+
46
+    // Background thread for the database
47
+    private Thread thread = null;
48
+    private Handler threadHandler = new Handler();
49
+
50
+    // Progress bar
51
+    private Progress progress = null;
52
+
53
+    // Add course dialog window
54
+    private AlertDialog addEditCourseDialog = null;
55
+    private View addEditCourseView;
56
+
57
+    private AlertDialog confirmDialog = null;
58
+
59
+    // Floating action button
60
+    private FloatingActionButton fab = null;
61
+
62
+    // Multi select
63
+    private boolean optionsSelected[] = null;
64
+
65
+    // RecyclerView
66
+    private RecyclerView recyclerView = null;
67
+    private CourseListAdapter courseListAdapter = null;
68
+
69
+    private Subject subject = null;
70
+
71
+    @Override
72
+    protected void onCreate(Bundle savedInstanceState) {
73
+        super.onCreate(savedInstanceState);
74
+
75
+        // Receive the subject from the previous activity
76
+        Intent subjectListIntent = getIntent();
77
+        subject = subjectListIntent.getParcelableExtra(StaticVariables.SUBJECT_OBJECT);
78
+
79
+        setContentView(R.layout.activity_course_list);
80
+        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
81
+        toolbar.setTitle(subject.getSubjectName());
82
+        toolbar.setSubtitle(subject.getMajorName());
83
+        setSupportActionBar(toolbar);
84
+        ActionBar actionBar = getSupportActionBar();
85
+        if (actionBar != null) {
86
+            actionBar.setHomeButtonEnabled(true);
87
+            actionBar.setDisplayHomeAsUpEnabled(true);
88
+        }
89
+
90
+        // Inflate the add course view
91
+        LayoutInflater inflater = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
92
+        addEditCourseView = inflater.inflate(R.layout.view_course_add_edit, new RelativeLayout(this), false);
93
+
94
+        // Build the add course dialog window using the course view
95
+        AlertDialog.Builder builder = new AlertDialog.Builder(this);
96
+        builder.setView(addEditCourseView);
97
+        builder.setPositiveButton(R.string.input_accept, null);
98
+        builder.setNegativeButton(R.string.input_cancel, new DialogInterface.OnClickListener() {
99
+            @Override
100
+            public void onClick(DialogInterface dialog, int which) {
101
+                eraseAddEditCourses();
102
+            }
103
+        });
104
+
105
+        builder.setCancelable(false);
106
+        addEditCourseDialog = builder.create();
107
+
108
+        addEditCourseDialog.setOnShowListener(new DialogInterface.OnShowListener() {
109
+            @Override
110
+            public void onShow(DialogInterface dialogInterface) {
111
+                addEditCourseDialog.getButton(AlertDialog.BUTTON_POSITIVE).setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.colorPrimaryDark));
112
+                addEditCourseDialog.getButton(AlertDialog.BUTTON_NEGATIVE).setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.colorPrimaryDark));
113
+            }
114
+        });
115
+
116
+        addEditCourseDialog.getWindow().getAttributes().windowAnimations = R.style.DialogAnimation;
117
+
118
+        fab = (FloatingActionButton) findViewById(R.id.fab);
119
+        fab.setOnClickListener(new View.OnClickListener() {
120
+            @Override
121
+            public void onClick(View view) {
122
+                addEditCourseDialog.setTitle(R.string.courses_add_course);
123
+                addEditCourseDialog.show();
124
+                addCourseListeners(); // Override the accept button!
125
+            }
126
+        });
127
+
128
+        // Create a progress dialog for slow devices
129
+        progress = new Progress();
130
+        progress.show(this, 1);
131
+        progress.setCancelable(false);
132
+
133
+        // Load the SQLite database
134
+        sqlParser = new SQLParser(this);
135
+        thread = new Thread(new Runnable() {
136
+            public void run() {
137
+                ubbDB = sqlParser.getWritableDatabase();
138
+                threadHandler.post(new Runnable() {
139
+                    public void run() {
140
+                        databaseLoaded();
141
+                    }
142
+                });
143
+            }
144
+        });
145
+        thread.start();
146
+        progress.setOnCancelListener(new DialogInterface.OnCancelListener() {
147
+            @Override
148
+            public void onCancel(DialogInterface dialog) {
149
+                thread.interrupt();
150
+                finish();
151
+            }
152
+        });
153
+    }
154
+
155
+    @Override
156
+    public void onActivityResult(int requestCode, int resultCode, Intent intent) {
157
+        super.onActivityResult(requestCode, resultCode, intent);
158
+        if (requestCode == 1) {
159
+            if(resultCode == RESULT_OK){
160
+                subject = intent.getParcelableExtra(StaticVariables.SUBJECT_OBJECT);
161
+            }
162
+        }
163
+    }
164
+
165
+    // After the view is added to the screen check to see if it needs to be selected
166
+    @Override
167
+    public void onWindowFocusChanged(boolean hasFocus) {
168
+        if(hasFocus){
169
+            // Restore the recycler view after recreation
170
+            if (optionsSelected != null) {
171
+                fab.hide();
172
+                for (int i = 0; i < optionsSelected.length; i++) {
173
+                    if (optionsSelected[i]) {
174
+                        CardView cardView = (CardView) recyclerView.getChildAt(i);
175
+                        cardView.setCardBackgroundColor(ContextCompat.getColor(getApplicationContext(), R.color.colorPrimarySelected));
176
+                    }
177
+                }
178
+            }
179
+        }
180
+    }
181
+
182
+    @Override
183
+    protected void onSaveInstanceState(Bundle state) {
184
+        super.onSaveInstanceState(state);
185
+
186
+        // Save the state of the dialog
187
+        if (addEditCourseDialog != null && addEditCourseDialog.isShowing()) {
188
+            state.putBoolean("add_dialog_showing", addEditCourseDialog.isShowing());
189
+            TextView textView = (TextView) addEditCourseDialog.findViewById(R.id.edit_year);
190
+            state.putString("add_dialog_year", textView.getText().toString());
191
+            textView = (TextView) addEditCourseDialog.findViewById(R.id.edit_semester);
192
+            state.putString("add_dialog_semester", textView.getText().toString());
193
+            textView = (TextView) addEditCourseDialog.findViewById(R.id.edit_section);
194
+            state.putString("add_dialog_section", textView.getText().toString());
195
+        }
196
+        // Save the state of the adapter
197
+        state.putBooleanArray("options_selected", optionsSelected);
198
+    }
199
+
200
+    @Override