From 5c65209f2bd5b53a82fae0bf310adc94e19eea84 Mon Sep 17 00:00:00 2001 From: aNNiMON Date: Wed, 14 Feb 2024 00:01:58 +0200 Subject: [PATCH] Initial commit --- .classpath | 9 + .project | 33 ++ AndroidManifest.xml | 55 +++ proguard-project.txt | 20 ++ project.properties | 16 + res/drawable-hdpi/drawer_shadow.9.png | Bin 0 -> 114 bytes res/drawable-hdpi/ic_action_export.png | Bin 0 -> 379 bytes res/drawable-hdpi/ic_action_new.png | Bin 0 -> 166 bytes res/drawable-hdpi/ic_drawer.png | Bin 0 -> 96 bytes res/drawable-hdpi/ic_launcher.png | Bin 0 -> 2478 bytes res/drawable-mdpi/drawer_shadow.9.png | Bin 0 -> 95 bytes res/drawable-mdpi/ic_action_export.png | Bin 0 -> 303 bytes res/drawable-mdpi/ic_action_new.png | Bin 0 -> 124 bytes res/drawable-mdpi/ic_drawer.png | Bin 0 -> 87 bytes res/drawable-mdpi/ic_launcher.png | Bin 0 -> 1722 bytes res/drawable-xhdpi/drawer_shadow.9.png | Bin 0 -> 129 bytes res/drawable-xhdpi/ic_action_export.png | Bin 0 -> 392 bytes res/drawable-xhdpi/ic_action_new.png | Bin 0 -> 170 bytes res/drawable-xhdpi/ic_drawer.png | Bin 0 -> 109 bytes res/drawable-xhdpi/ic_launcher.png | Bin 0 -> 3191 bytes res/drawable-xxhdpi/drawer_shadow.9.png | Bin 0 -> 157 bytes res/drawable-xxhdpi/ic_action_new.png | Bin 0 -> 231 bytes res/drawable-xxhdpi/ic_drawer.png | Bin 0 -> 111 bytes res/drawable-xxhdpi/ic_launcher.png | Bin 0 -> 4948 bytes res/drawable/ab_background.xml | 9 + res/drawable/bg_table_header.xml | 7 + res/drawable/bg_table_item1.xml | 7 + res/drawable/bg_table_item2.xml | 7 + res/drawable/list_selector.xml | 10 + res/layout-sw600dp-land/activity_main.xml | 34 ++ res/layout/activity_main.xml | 39 +++ res/layout/dialog_add_criteria.xml | 32 ++ res/layout/dialog_add_group.xml | 19 ++ res/layout/dialog_add_mark.xml | 19 ++ res/layout/dialog_add_student.xml | 41 +++ res/layout/dialog_add_subject.xml | 28 ++ res/layout/fragment_main.xml | 29 ++ res/layout/fragment_navigation_drawer.xml | 9 + res/layout/fragment_table.xml | 17 + res/layout/item_nav_drawer.xml | 10 + res/menu/add_item.xml | 11 + res/menu/item_context.xml | 11 + res/menu/main.xml | 11 + res/values-v11/styles.xml | 19 ++ res/values/colors.xml | 9 + res/values/dimens.xml | 9 + res/values/strings.xml | 36 ++ res/values/styles.xml | 27 ++ res/xml/authenticator.xml | 6 + res/xml/db_sync.xml | 8 + .../university/journal/EmptyTableAdapter.java | 66 ++++ src/com/university/journal/MainActivity.java | 104 ++++++ .../university/journal/MarksTableAdapter.java | 117 +++++++ .../journal/NavigationDrawerFragment.java | 230 +++++++++++++ .../journal/accounts/AccountService.java | 20 ++ .../journal/accounts/Authenticator.java | 110 ++++++ .../university/journal/db/ContentManager.java | 83 +++++ .../journal/db/DbContentProvider.java | 313 ++++++++++++++++++ src/com/university/journal/db/DbContract.java | 103 ++++++ .../university/journal/db/DbOpenHelper.java | 42 +++ src/com/university/journal/db/DbSchema.java | 56 ++++ .../university/journal/entity/Criteria.java | 77 +++++ .../journal/entity/DatabaseSerializer.java | 11 + src/com/university/journal/entity/Group.java | 47 +++ src/com/university/journal/entity/Mark.java | 70 ++++ .../journal/entity/MarksTableItem.java | 24 ++ .../university/journal/entity/Student.java | 83 +++++ .../university/journal/entity/Subject.java | 58 ++++ .../journal/fragments/CriteriaFragment.java | 62 ++++ .../journal/fragments/DbTableFragment.java | 146 ++++++++ .../journal/fragments/GroupFragment.java | 51 +++ .../journal/fragments/MainFragment.java | 244 ++++++++++++++ .../fragments/NewCriteriaDialogFragment.java | 77 +++++ .../fragments/NewGroupDialogFragment.java | 43 +++ .../fragments/NewItemDialogFragment.java | 51 +++ .../fragments/NewMarkDialogFragment.java | 79 +++++ .../fragments/NewStudentDialogFragment.java | 72 ++++ .../fragments/NewSubjectDialogFragment.java | 48 +++ .../journal/fragments/StudentFragment.java | 105 ++++++ .../journal/fragments/SubjectFragment.java | 51 +++ 80 files changed, 3240 insertions(+) create mode 100644 .classpath create mode 100644 .project create mode 100644 AndroidManifest.xml create mode 100644 proguard-project.txt create mode 100644 project.properties create mode 100644 res/drawable-hdpi/drawer_shadow.9.png create mode 100644 res/drawable-hdpi/ic_action_export.png create mode 100644 res/drawable-hdpi/ic_action_new.png create mode 100644 res/drawable-hdpi/ic_drawer.png create mode 100644 res/drawable-hdpi/ic_launcher.png create mode 100644 res/drawable-mdpi/drawer_shadow.9.png create mode 100644 res/drawable-mdpi/ic_action_export.png create mode 100644 res/drawable-mdpi/ic_action_new.png create mode 100644 res/drawable-mdpi/ic_drawer.png create mode 100644 res/drawable-mdpi/ic_launcher.png create mode 100644 res/drawable-xhdpi/drawer_shadow.9.png create mode 100644 res/drawable-xhdpi/ic_action_export.png create mode 100644 res/drawable-xhdpi/ic_action_new.png create mode 100644 res/drawable-xhdpi/ic_drawer.png create mode 100644 res/drawable-xhdpi/ic_launcher.png create mode 100644 res/drawable-xxhdpi/drawer_shadow.9.png create mode 100644 res/drawable-xxhdpi/ic_action_new.png create mode 100644 res/drawable-xxhdpi/ic_drawer.png create mode 100644 res/drawable-xxhdpi/ic_launcher.png create mode 100644 res/drawable/ab_background.xml create mode 100644 res/drawable/bg_table_header.xml create mode 100644 res/drawable/bg_table_item1.xml create mode 100644 res/drawable/bg_table_item2.xml create mode 100644 res/drawable/list_selector.xml create mode 100644 res/layout-sw600dp-land/activity_main.xml create mode 100644 res/layout/activity_main.xml create mode 100644 res/layout/dialog_add_criteria.xml create mode 100644 res/layout/dialog_add_group.xml create mode 100644 res/layout/dialog_add_mark.xml create mode 100644 res/layout/dialog_add_student.xml create mode 100644 res/layout/dialog_add_subject.xml create mode 100644 res/layout/fragment_main.xml create mode 100644 res/layout/fragment_navigation_drawer.xml create mode 100644 res/layout/fragment_table.xml create mode 100644 res/layout/item_nav_drawer.xml create mode 100644 res/menu/add_item.xml create mode 100644 res/menu/item_context.xml create mode 100644 res/menu/main.xml create mode 100644 res/values-v11/styles.xml create mode 100644 res/values/colors.xml create mode 100644 res/values/dimens.xml create mode 100644 res/values/strings.xml create mode 100644 res/values/styles.xml create mode 100644 res/xml/authenticator.xml create mode 100644 res/xml/db_sync.xml create mode 100644 src/com/university/journal/EmptyTableAdapter.java create mode 100644 src/com/university/journal/MainActivity.java create mode 100644 src/com/university/journal/MarksTableAdapter.java create mode 100644 src/com/university/journal/NavigationDrawerFragment.java create mode 100644 src/com/university/journal/accounts/AccountService.java create mode 100644 src/com/university/journal/accounts/Authenticator.java create mode 100644 src/com/university/journal/db/ContentManager.java create mode 100644 src/com/university/journal/db/DbContentProvider.java create mode 100644 src/com/university/journal/db/DbContract.java create mode 100644 src/com/university/journal/db/DbOpenHelper.java create mode 100644 src/com/university/journal/db/DbSchema.java create mode 100644 src/com/university/journal/entity/Criteria.java create mode 100644 src/com/university/journal/entity/DatabaseSerializer.java create mode 100644 src/com/university/journal/entity/Group.java create mode 100644 src/com/university/journal/entity/Mark.java create mode 100644 src/com/university/journal/entity/MarksTableItem.java create mode 100644 src/com/university/journal/entity/Student.java create mode 100644 src/com/university/journal/entity/Subject.java create mode 100644 src/com/university/journal/fragments/CriteriaFragment.java create mode 100644 src/com/university/journal/fragments/DbTableFragment.java create mode 100644 src/com/university/journal/fragments/GroupFragment.java create mode 100644 src/com/university/journal/fragments/MainFragment.java create mode 100644 src/com/university/journal/fragments/NewCriteriaDialogFragment.java create mode 100644 src/com/university/journal/fragments/NewGroupDialogFragment.java create mode 100644 src/com/university/journal/fragments/NewItemDialogFragment.java create mode 100644 src/com/university/journal/fragments/NewMarkDialogFragment.java create mode 100644 src/com/university/journal/fragments/NewStudentDialogFragment.java create mode 100644 src/com/university/journal/fragments/NewSubjectDialogFragment.java create mode 100644 src/com/university/journal/fragments/StudentFragment.java create mode 100644 src/com/university/journal/fragments/SubjectFragment.java diff --git a/.classpath b/.classpath new file mode 100644 index 0000000..5176974 --- /dev/null +++ b/.classpath @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.project b/.project new file mode 100644 index 0000000..803c16e --- /dev/null +++ b/.project @@ -0,0 +1,33 @@ + + + Journal + + + + + + com.android.ide.eclipse.adt.ResourceManagerBuilder + + + + + com.android.ide.eclipse.adt.PreCompilerBuilder + + + + + org.eclipse.jdt.core.javabuilder + + + + + com.android.ide.eclipse.adt.ApkBuilder + + + + + + com.android.ide.eclipse.adt.AndroidNature + org.eclipse.jdt.core.javanature + + diff --git a/AndroidManifest.xml b/AndroidManifest.xml new file mode 100644 index 0000000..ae8be26 --- /dev/null +++ b/AndroidManifest.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proguard-project.txt b/proguard-project.txt new file mode 100644 index 0000000..f2fe155 --- /dev/null +++ b/proguard-project.txt @@ -0,0 +1,20 @@ +# To enable ProGuard in your project, edit project.properties +# to define the proguard.config property as described in that file. +# +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in ${sdk.dir}/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the ProGuard +# include property in project.properties. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/project.properties b/project.properties new file mode 100644 index 0000000..e999993 --- /dev/null +++ b/project.properties @@ -0,0 +1,16 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system edit +# "ant.properties", and override values to adapt the script to your +# project structure. +# +# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): +#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt + +# Project target. +target=android-19 +android.library.reference.1=..\\TableFixHeaders +android.library.reference.2=../android-support-v7-appcompat diff --git a/res/drawable-hdpi/drawer_shadow.9.png b/res/drawable-hdpi/drawer_shadow.9.png new file mode 100644 index 0000000000000000000000000000000000000000..aebc557fe5a6bffb46ce0268825825fad4b2ce77 GIT binary patch literal 114 zcmeAS@N?(olHy`uVBq!ia0vp^JV0#3!3HEVSgovpl%=POV@SoV0fhdEP)fnFtJ1`)c6k@)YGx#1n zOoI1vpCp%DzG<~6ilQi8isSg%b=^^*?b41kTF>pv^F+%|+XD04)%81BgSI01$;R1t11t z5*!PEP_z@wW7D3NUj0Nd6$lD}1rtc|HNP^$@$6S&3i zQiqS(%^1W5?+6J22+$M&HA{qd0-h4!+Dj-+(}$`?Oq*liUI+0bCS@O0je1ev2mp#y zU5U94DswYqX8`Z33jq%}1_;nFfEBj?=&;Hb1t=)5*Xl}zt-KE$bz1FP^?{$7D2k%A Z=>P}%Y57KodiwwX002ovPDHLkV1gcep1S}5 literal 0 HcmV?d00001 diff --git a/res/drawable-hdpi/ic_action_new.png b/res/drawable-hdpi/ic_action_new.png new file mode 100644 index 0000000000000000000000000000000000000000..95eb9ea79462f71a676a973f731313faf49b70e2 GIT binary patch literal 166 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 Tv+p=IfkZrA{an^LB{Ts5)5j#2 literal 0 HcmV?d00001 diff --git a/res/drawable-mdpi/ic_drawer.png b/res/drawable-mdpi/ic_drawer.png new file mode 100644 index 0000000000000000000000000000000000000000..08eaf5071c52a1d4471ae8f0c84c4f453f62b381 GIT binary patch literal 87 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`a-J@ZAr-fh6BdY=m~H*1&c>g_ k+{P%;+j=o#K^r5(>XVPlfBoAo2vo`7>FVdQ&MBb@0Bd*{#sB~S literal 0 HcmV?d00001 diff --git a/res/drawable-mdpi/ic_launcher.png b/res/drawable-mdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..f7a57a81100fbd4fcbd07a5f0a9faa020fb79d1e GIT binary patch literal 1722 zcmV;r21WUaP)_+Zo*AJoJb6Jkhw z6oaWg*2I!D@0I5LA{`x*Gp7@e&?Bdk73K#{WWFT^nqCXQLO>PgykJcJ%z>JdFQ5 z4zesmiB!Vtk&j1Q3-IK{6PWmA0(3H8VjyF zdSDby0OeUubEI|kCq0cfsiwwRmVbO<^hFF%Ic4{onOs`?9e zhM{9qhtL*{Irqak$fmQaJBe`@+k@?v=aFQ@@~pn99$IQzTzOzJo3uRJykRr6ZECaS z;f;q9!HOX4Zrg3J`I_g3Q7K7kp{x91h7Pi#X$TVacM%vL6AFm+|u=X*ZKLuom#yD z>jQA|last{?58nUjxF=~aBf7aq23`LN+3)o(@7Cl^la&Y!4C(m@ay1@jvC;LfqN}H zk3WZn=z>5cy+JO=mw6ir5GW6bjaqoMzz-@saj_i(z1P+N4fLV`fmNmG0%lGt!Wn66^!ZwFSmqt zjZq_o2UTTNqOG;IRfNhocT-i978A?RwYiJOU9{$wnk}{_WHM*Toey}>z>)Wl*gk*y z@+s^M?X_t5S>zc6Hw58S|Ec_%1#KglR}}K-15R{y@~puu2^=t-xcbFa_r3)leSq5} zGe&`<)1xpwH_cU#p*BXVH;>=s@%n|S3;Z>aqE-wS#y%h8alQFqBzwoUW8WU*FGGB% zRcGI|br+l-IQ{x4L{4Yf4RsN;K&CM8DLxC*P{x6TC-gC&FN9JApR{3St@C#9ib4)1 zg#Xi98fw9UG{}^+vM>_%7wTtL?b1CVkQ0o04(8}&w4Drpl48_=CLC#i#@cBBYc3!I z@#?5Q3oLwCeIS1@=i~$18@EHLuTf9q(TRTtg?L85 zqydam;_0~9140|DF<470Y0($`1flZs{>wZOMm~Xam&&D3y}sJh3GW$&><+RkKVE^m zzun~yjHZJyIyF26z7ijtpE?f@{(K<%HdHmht>d@&{m6GC{6Hh^qA4Q8x)mTFlzKuT z(hMe}aM$&!HSd(+o)C)sOYt5gu1W)TFiK4GfXyc2B=d4=BM0{KLgUs4EGT3r05U=` zzn&2eqblO?oDc*1XjG>yFB%}ncmGbz><U=}_VZ##`$GF1nK-=t@N2yjugV9CDJ!w+%$%2Z z;LPMqrQ?%t->nDZ#t zq?C(?o2C+CPdOs08Af5w6bRCAMPpGy#OU# QhyVZp07*qoM6N<$g1bCA>Hq)$ literal 0 HcmV?d00001 diff --git a/res/drawable-xhdpi/drawer_shadow.9.png b/res/drawable-xhdpi/drawer_shadow.9.png new file mode 100644 index 0000000000000000000000000000000000000000..0fe08f4f3f5038c2764e6c9c852075284a662b42 GIT binary patch literal 129 zcmeAS@N?(olHy`uVBq!ia0vp^{6Or)!3HEd1bTh|DGyH<$B>F!Z_g~`Wl$7gy~r!& z%Ie|eaEW==ztas9R|wyj?W-2~x$emAx4$DzG6R;oP321Uif2yR7@;H9eH2XnXL;ZL ah{1TlrcGY18vB4|GI+ZBxvXJc{m<>WQ4!2=Qc#CU#dQPM1fGLN z4ni!i8D4Q@GX%Isa3AI`g=e^uBx14NK>-t!3PELP>k= zsUQB!7<Nn$?{Q*3=9X9Ik3nBh0GcL f{Edy9q#~Qo#I$&`L5|0PPLM)RS3j3^P61P9jt|LYI<2{2|X6ldr%*Z$o1yl4kd0fVQjpUXO@geCx8 CejYUd literal 0 HcmV?d00001 diff --git a/res/drawable-xhdpi/ic_launcher.png b/res/drawable-xhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..154a61ec93f55013a409fe19821034db4279f39f GIT binary patch literal 3191 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 literal 0 HcmV?d00001 diff --git a/res/drawable-xxhdpi/drawer_shadow.9.png b/res/drawable-xxhdpi/drawer_shadow.9.png new file mode 100644 index 0000000000000000000000000000000000000000..bfeb2dbfe288b90676afdeae48200de4314b00f7 GIT binary patch literal 157 zcmeAS@N?(olHy`uVBq!ia0vp^VnCe4!3HEl*p=S^sT5Ba$B>F!Z_g<5H8?OZALM3g zJoF&ILr197=`+*6{~e2kIxSq6om2}A_WFJG`_9W#&y_5(&CT@no^^T3F_R^BrSSy@ n5pWc?Ln>~)y}O%}L4n8NpwDBb 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 S{J*#W0000 + + + + + diff --git a/res/drawable/bg_table_header.xml b/res/drawable/bg_table_header.xml new file mode 100644 index 0000000..6380354 --- /dev/null +++ b/res/drawable/bg_table_header.xml @@ -0,0 +1,7 @@ + + + + + + diff --git a/res/drawable/bg_table_item1.xml b/res/drawable/bg_table_item1.xml new file mode 100644 index 0000000..716ea90 --- /dev/null +++ b/res/drawable/bg_table_item1.xml @@ -0,0 +1,7 @@ + + + + + + diff --git a/res/drawable/bg_table_item2.xml b/res/drawable/bg_table_item2.xml new file mode 100644 index 0000000..4996e20 --- /dev/null +++ b/res/drawable/bg_table_item2.xml @@ -0,0 +1,7 @@ + + + + + + diff --git a/res/drawable/list_selector.xml b/res/drawable/list_selector.xml new file mode 100644 index 0000000..ebe1937 --- /dev/null +++ b/res/drawable/list_selector.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/res/layout-sw600dp-land/activity_main.xml b/res/layout-sw600dp-land/activity_main.xml new file mode 100644 index 0000000..b525ea7 --- /dev/null +++ b/res/layout-sw600dp-land/activity_main.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + diff --git a/res/layout/activity_main.xml b/res/layout/activity_main.xml new file mode 100644 index 0000000..fb5fa5c --- /dev/null +++ b/res/layout/activity_main.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + diff --git a/res/layout/dialog_add_criteria.xml b/res/layout/dialog_add_criteria.xml new file mode 100644 index 0000000..97dfabd --- /dev/null +++ b/res/layout/dialog_add_criteria.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/res/layout/dialog_add_group.xml b/res/layout/dialog_add_group.xml new file mode 100644 index 0000000..9c01d13 --- /dev/null +++ b/res/layout/dialog_add_group.xml @@ -0,0 +1,19 @@ + + + + + + + + + \ No newline at end of file diff --git a/res/layout/dialog_add_mark.xml b/res/layout/dialog_add_mark.xml new file mode 100644 index 0000000..071be8a --- /dev/null +++ b/res/layout/dialog_add_mark.xml @@ -0,0 +1,19 @@ + + + + + + + + + \ No newline at end of file diff --git a/res/layout/dialog_add_student.xml b/res/layout/dialog_add_student.xml new file mode 100644 index 0000000..47eed17 --- /dev/null +++ b/res/layout/dialog_add_student.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/layout/dialog_add_subject.xml b/res/layout/dialog_add_subject.xml new file mode 100644 index 0000000..9588edf --- /dev/null +++ b/res/layout/dialog_add_subject.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/res/layout/fragment_main.xml b/res/layout/fragment_main.xml new file mode 100644 index 0000000..171ea55 --- /dev/null +++ b/res/layout/fragment_main.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/res/layout/fragment_navigation_drawer.xml b/res/layout/fragment_navigation_drawer.xml new file mode 100644 index 0000000..af78aac --- /dev/null +++ b/res/layout/fragment_navigation_drawer.xml @@ -0,0 +1,9 @@ + \ No newline at end of file diff --git a/res/layout/fragment_table.xml b/res/layout/fragment_table.xml new file mode 100644 index 0000000..302441b --- /dev/null +++ b/res/layout/fragment_table.xml @@ -0,0 +1,17 @@ + + + + + + + + + \ No newline at end of file diff --git a/res/layout/item_nav_drawer.xml b/res/layout/item_nav_drawer.xml new file mode 100644 index 0000000..05747f7 --- /dev/null +++ b/res/layout/item_nav_drawer.xml @@ -0,0 +1,10 @@ + + \ No newline at end of file diff --git a/res/menu/add_item.xml b/res/menu/add_item.xml new file mode 100644 index 0000000..74f9fa0 --- /dev/null +++ b/res/menu/add_item.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/res/menu/item_context.xml b/res/menu/item_context.xml new file mode 100644 index 0000000..de18de3 --- /dev/null +++ b/res/menu/item_context.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/res/menu/main.xml b/res/menu/main.xml new file mode 100644 index 0000000..4f483dd --- /dev/null +++ b/res/menu/main.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/res/values-v11/styles.xml b/res/values-v11/styles.xml new file mode 100644 index 0000000..5b7fc04 --- /dev/null +++ b/res/values-v11/styles.xml @@ -0,0 +1,19 @@ + + + + + + + + diff --git a/res/values/colors.xml b/res/values/colors.xml new file mode 100644 index 0000000..1301d34 --- /dev/null +++ b/res/values/colors.xml @@ -0,0 +1,9 @@ + + + #E2F3E4 + #51BB5B + #3FA348 + + #C4E6C8 + #89D191 + diff --git a/res/values/dimens.xml b/res/values/dimens.xml new file mode 100644 index 0000000..d7a42fb --- /dev/null +++ b/res/values/dimens.xml @@ -0,0 +1,9 @@ + + + + 240dp + + diff --git a/res/values/strings.xml b/res/values/strings.xml new file mode 100644 index 0000000..673337c --- /dev/null +++ b/res/values/strings.xml @@ -0,0 +1,36 @@ + + + + Журнал преподавателя + Open navigation drawer + Close navigation drawer + Действие + Настройки + Добавить + Экспорт + + Разрешён только один аккаунт + Пожалуйста, подождите… + Нет данных для отображения + Ошибка.\nПроверьте правильность ввода + Сохранено + + Название + Сокращение + Фамилия + Имя + Отчество + Дата (yyyy-MM-dd) + Оценка или текст + + Добавить + Удалить + + + Журнал + Дисциплины + Критерии оценки + Группы + Студенты + + diff --git a/res/values/styles.xml b/res/values/styles.xml new file mode 100644 index 0000000..e2a136e --- /dev/null +++ b/res/values/styles.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + diff --git a/res/xml/authenticator.xml b/res/xml/authenticator.xml new file mode 100644 index 0000000..85730c5 --- /dev/null +++ b/res/xml/authenticator.xml @@ -0,0 +1,6 @@ + + \ No newline at end of file diff --git a/res/xml/db_sync.xml b/res/xml/db_sync.xml new file mode 100644 index 0000000..d0c8ce7 --- /dev/null +++ b/res/xml/db_sync.xml @@ -0,0 +1,8 @@ + + \ No newline at end of file diff --git a/src/com/university/journal/EmptyTableAdapter.java b/src/com/university/journal/EmptyTableAdapter.java new file mode 100644 index 0000000..8fb2864 --- /dev/null +++ b/src/com/university/journal/EmptyTableAdapter.java @@ -0,0 +1,66 @@ +package com.university.journal; + +import android.content.Context; +import android.database.DataSetObserver; +import android.view.View; +import android.view.ViewGroup; +import com.inqbarna.tablefixheaders.adapters.TableAdapter; + +/** + * Empty adapter for marks table. + */ +public final class EmptyTableAdapter implements TableAdapter { + + private final Context mContext; + + public EmptyTableAdapter(Context context) { + this.mContext = context; + } + + @Override + public void registerDataSetObserver(DataSetObserver observer) { + } + + @Override + public void unregisterDataSetObserver(DataSetObserver observer) { + } + + @Override + public int getRowCount() { + return 1; + } + + @Override + public int getColumnCount() { + return 1; + } + + @Override + public View getView(int row, int column, View convertView, ViewGroup parent) { + if (convertView == null) { + convertView = new View(mContext); + } + return convertView; + } + + @Override + public int getWidth(int column) { + return 200; + } + + @Override + public int getHeight(int row) { + return 100; + } + + @Override + public int getItemViewType(int row, int column) { + return 0; + } + + @Override + public int getViewTypeCount() { + return 1; + } + +} diff --git a/src/com/university/journal/MainActivity.java b/src/com/university/journal/MainActivity.java new file mode 100644 index 0000000..ebf60ee --- /dev/null +++ b/src/com/university/journal/MainActivity.java @@ -0,0 +1,104 @@ +package com.university.journal; + +import static com.university.journal.accounts.Authenticator.ACCOUNT_TYPE; +import android.accounts.Account; +import android.accounts.AccountManager; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.widget.DrawerLayout; +import android.support.v7.app.ActionBar; +import android.support.v7.app.ActionBarActivity; +import com.university.journal.accounts.Authenticator; +import com.university.journal.fragments.CriteriaFragment; +import com.university.journal.fragments.GroupFragment; +import com.university.journal.fragments.MainFragment; +import com.university.journal.fragments.StudentFragment; +import com.university.journal.fragments.SubjectFragment; + +public final class MainActivity extends ActionBarActivity + implements NavigationDrawerFragment.NavigationDrawerCallbacks { + + /** + * Fragment managing the behaviors, interactions and presentation of the + * navigation drawer. + */ + private NavigationDrawerFragment mNavigationDrawerFragment; + + /** + * Used to store the last screen title. For use in + * {@link #restoreActionBar()}. + */ + private CharSequence mTitle; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + final AccountManager accountManager = AccountManager.get(this); + final Account[] accounts = accountManager.getAccountsByType(ACCOUNT_TYPE); + if (accounts.length == 0) { + final String login = getString(R.string.app_name); + Authenticator.addAccount(login, accountManager); + } + + setContentView(R.layout.activity_main); + + mNavigationDrawerFragment = (NavigationDrawerFragment) getSupportFragmentManager() + .findFragmentById(R.id.navigation_drawer); + mTitle = getTitle(); + + if (mNavigationDrawerFragment != null) { + // Set up the drawer. + mNavigationDrawerFragment.setUp(R.id.navigation_drawer, + (DrawerLayout) findViewById(R.id.drawer_layout)); + } + } + + @Override + public void onNavigationDrawerItemSelected(int position) { + // update the main content by replacing fragments + Fragment frag = null; + + switch (position) { + case 0: // + frag = new MainFragment(); + break; + case 1: // + frag = new SubjectFragment(); + break; + case 2: // + frag = new CriteriaFragment(); + break; + case 3: // + frag = new GroupFragment(); + break; + case 4: // + frag = new StudentFragment(); + break; + } + + if (frag == null) return; + + onSectionAttached(position); + + FragmentManager fragmentManager = getSupportFragmentManager(); + fragmentManager + .beginTransaction() + .replace(R.id.container, frag).commit(); + } + + private void onSectionAttached(int number) { + final String[] titles = getResources().getStringArray(R.array.nav_sections); + mTitle = titles[number]; + restoreActionBar(); + } + + private void restoreActionBar() { + ActionBar actionBar = getSupportActionBar(); + if (actionBar == null) return; + actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD); + actionBar.setDisplayShowTitleEnabled(true); + actionBar.setTitle(mTitle); + } +} diff --git a/src/com/university/journal/MarksTableAdapter.java b/src/com/university/journal/MarksTableAdapter.java new file mode 100644 index 0000000..2b7890f --- /dev/null +++ b/src/com/university/journal/MarksTableAdapter.java @@ -0,0 +1,117 @@ +package com.university.journal; + +import android.content.Context; +import android.util.DisplayMetrics; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.TextView; +import com.inqbarna.tablefixheaders.adapters.BaseTableAdapter; +import com.university.journal.entity.Criteria; +import com.university.journal.entity.MarksTableItem; + +public final class MarksTableAdapter extends BaseTableAdapter { + + private static final int VIEW_TYPE_HEADER = 0, VIEW_TYPE_MARK = 1; + + private final Context mContext; + private final Criteria[] mHeaders; + private final MarksTableItem[] mItems; + private final int mColumnHeaderHeight, mRowHeaderWidth, mWidth, mHeight; + + private View.OnClickListener mMarkClickListener; + + public MarksTableAdapter(Context context, Criteria[] headers, MarksTableItem[] items) { + mContext = context; + mHeaders = headers; + mItems = items; + + DisplayMetrics dm = context.getResources().getDisplayMetrics(); + mRowHeaderWidth = Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 125, dm)); + mWidth = Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 100, dm)); + mColumnHeaderHeight = Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 60, dm)); + mHeight = Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 40, dm)); + } + + public Criteria getHeader(int column) { + return mHeaders[column]; + } + + public MarksTableItem getItem(int row) { + return mItems[row]; + } + + public void setMarkClickListener(View.OnClickListener markClickListener) { + mMarkClickListener = markClickListener; + } + + @Override + public int getRowCount() { + return mItems.length; + } + + @Override + public int getColumnCount() { + return mHeaders.length; + } + + @Override + public View getView(int row, int column, View convertView, ViewGroup parent) { + switch (getItemViewType(row, column)) { + case VIEW_TYPE_HEADER: + if (convertView == null) { + convertView = new TextView(mContext); + convertView.setBackgroundResource(R.drawable.bg_table_header); + } + if (row == -1 && column == -1) break; + if (row == -1) { + // Column header - Criteries + ((TextView) convertView).setText(mHeaders[column].readableString()); + ((TextView) convertView).setGravity(Gravity.CENTER_HORIZONTAL); + } else { + // Row header - Students + ((TextView) convertView).setText(mItems[row].getStudent().readableString()); + ((TextView) convertView).setGravity(Gravity.CENTER_VERTICAL); + } + break; + case VIEW_TYPE_MARK: + if (convertView == null) { + convertView = new Button(mContext); + convertView.setOnClickListener(mMarkClickListener); + } + final Button btn = (Button) convertView; + btn.setText(mItems[row].getMark(column).getMark()); + + final int resId = (row % 2 == 0) ? + R.drawable.bg_table_item1 : R.drawable.bg_table_item2; + convertView.setBackgroundResource(resId); + break; + } + + return convertView; + } + + @Override + public int getWidth(int column) { + return (column == -1) ? mRowHeaderWidth : mWidth; + } + + @Override + public int getHeight(int row) { + return (row == -1) ? mColumnHeaderHeight : mHeight; + } + + @Override + public int getItemViewType(int row, int column) { + if (row == -1 || column == -1) return VIEW_TYPE_HEADER; + return VIEW_TYPE_MARK; + } + + @Override + public int getViewTypeCount() { + return 2; + } + +} diff --git a/src/com/university/journal/NavigationDrawerFragment.java b/src/com/university/journal/NavigationDrawerFragment.java new file mode 100644 index 0000000..94e6f5c --- /dev/null +++ b/src/com/university/journal/NavigationDrawerFragment.java @@ -0,0 +1,230 @@ +package com.university.journal; + +import android.app.Activity; +import android.content.SharedPreferences; +import android.content.res.Configuration; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.support.v4.app.ActionBarDrawerToggle; +import android.support.v4.app.Fragment; +import android.support.v4.view.GravityCompat; +import android.support.v4.widget.DrawerLayout; +import android.support.v7.app.ActionBar; +import android.support.v7.app.ActionBarActivity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.ListView; + +/** + * Fragment used for managing interactions for and presentation of a navigation drawer. + * See the + * design guidelines for a complete explanation of the behaviors implemented here. + */ +public final class NavigationDrawerFragment extends Fragment { + + /** + * Remember the position of the selected item. + */ + private static final String STATE_SELECTED_POSITION = "selected_navigation_drawer_position"; + + /** + * Per the design guidelines, you should show the drawer on launch until the user manually + * expands it. This shared preference tracks this. + */ + private static final String PREF_USER_LEARNED_DRAWER = "navigation_drawer_learned"; + + /** + * A pointer to the current callbacks instance (the Activity). + */ + private NavigationDrawerCallbacks mCallbacks; + + /** + * Helper component that ties the action bar to the navigation drawer. + */ + private ActionBarDrawerToggle mDrawerToggle; + + private DrawerLayout mDrawerLayout; + private ListView mDrawerListView; + private View mFragmentContainerView; + + private int mCurrentSelectedPosition = 0; + private boolean mFromSavedInstanceState; + private boolean mUserLearnedDrawer; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // Read in the flag indicating whether or not the user has demonstrated awareness of the + // drawer. See PREF_USER_LEARNED_DRAWER for details. + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getActivity()); + mUserLearnedDrawer = sp.getBoolean(PREF_USER_LEARNED_DRAWER, false); + + if (savedInstanceState != null) { + mCurrentSelectedPosition = savedInstanceState.getInt(STATE_SELECTED_POSITION); + mFromSavedInstanceState = true; + } + + // Select either the default item (0) or the last selected item. + selectItem(mCurrentSelectedPosition); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + mDrawerListView = (ListView) inflater.inflate( + R.layout.fragment_navigation_drawer, container, false); + mDrawerListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + selectItem(position); + } + }); + mDrawerListView.setAdapter(new ArrayAdapter<>( + getActionBar().getThemedContext(), + R.layout.item_nav_drawer, + android.R.id.text1, + getResources().getStringArray(R.array.nav_sections))); + mDrawerListView.setItemChecked(mCurrentSelectedPosition, true); + return mDrawerListView; + } + + public boolean isDrawerOpen() { + return mDrawerLayout != null && mDrawerLayout.isDrawerOpen(mFragmentContainerView); + } + + /** + * Users of this fragment must call this method to set up the navigation drawer interactions. + * + * @param fragmentId The android:id of this fragment in its activity's layout. + * @param drawerLayout The DrawerLayout containing this fragment's UI. + */ + public void setUp(int fragmentId, DrawerLayout drawerLayout) { + mFragmentContainerView = getActivity().findViewById(fragmentId); + mDrawerLayout = drawerLayout; + if (mDrawerLayout == null) return; + + // set a custom shadow that overlays the main content when the drawer opens + mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START); + // set up the drawer's list view with items and click listener + + ActionBar actionBar = getActionBar(); + actionBar.setDisplayHomeAsUpEnabled(true); + actionBar.setHomeButtonEnabled(true); + + // ActionBarDrawerToggle ties together the the proper interactions + // between the navigation drawer and the action bar app icon. + + mDrawerToggle = new ActionBarDrawerToggle( + getActivity(), /* host Activity */ + mDrawerLayout, /* DrawerLayout object */ + R.drawable.ic_drawer, /* nav drawer image to replace 'Up' caret */ + R.string.navigation_drawer_open, /* "open drawer" description for accessibility */ + R.string.navigation_drawer_close /* "close drawer" description for accessibility */ + ) { + @Override + public void onDrawerClosed(View drawerView) { + super.onDrawerClosed(drawerView); + if (!isAdded()) { + return; + } + + getActivity().supportInvalidateOptionsMenu(); // calls onPrepareOptionsMenu() + } + + @Override + public void onDrawerOpened(View drawerView) { + super.onDrawerOpened(drawerView); + if (!isAdded()) { + return; + } + + if (!mUserLearnedDrawer) { + // The user manually opened the drawer; store this flag to prevent auto-showing + // the navigation drawer automatically in the future. + mUserLearnedDrawer = true; + SharedPreferences sp = PreferenceManager + .getDefaultSharedPreferences(getActivity()); + sp.edit().putBoolean(PREF_USER_LEARNED_DRAWER, true).commit(); + } + + getActivity().supportInvalidateOptionsMenu(); // calls onPrepareOptionsMenu() + } + }; + + // If the user hasn't 'learned' about the drawer, open it to introduce them to the drawer, + // per the navigation drawer design guidelines. + if (!mUserLearnedDrawer && !mFromSavedInstanceState) { + mDrawerLayout.openDrawer(mFragmentContainerView); + } + + // Defer code dependent on restoration of previous instance state. + mDrawerLayout.post(new Runnable() { + @Override + public void run() { + mDrawerToggle.syncState(); + } + }); + + mDrawerLayout.setDrawerListener(mDrawerToggle); + } + + private void selectItem(int position) { + mCurrentSelectedPosition = position; + if (mDrawerListView != null) { + mDrawerListView.setItemChecked(position, true); + } + if (mDrawerLayout != null) { + mDrawerLayout.closeDrawer(mFragmentContainerView); + } + if (mCallbacks != null) { + mCallbacks.onNavigationDrawerItemSelected(position); + } + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + try { + mCallbacks = (NavigationDrawerCallbacks) activity; + } catch (ClassCastException e) { + throw new ClassCastException("Activity must implement NavigationDrawerCallbacks."); + } + } + + @Override + public void onDetach() { + super.onDetach(); + mCallbacks = null; + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putInt(STATE_SELECTED_POSITION, mCurrentSelectedPosition); + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + // Forward the new configuration the drawer toggle component. + mDrawerToggle.onConfigurationChanged(newConfig); + } + + private ActionBar getActionBar() { + return ((ActionBarActivity) getActivity()).getSupportActionBar(); + } + + /** + * Callbacks interface that all activities using this fragment must implement. + */ + public static interface NavigationDrawerCallbacks { + /** + * Called when an item in the navigation drawer is selected. + */ + void onNavigationDrawerItemSelected(int position); + } +} diff --git a/src/com/university/journal/accounts/AccountService.java b/src/com/university/journal/accounts/AccountService.java new file mode 100644 index 0000000..404c754 --- /dev/null +++ b/src/com/university/journal/accounts/AccountService.java @@ -0,0 +1,20 @@ +package com.university.journal.accounts; + +import android.app.Service; +import android.content.Intent; +import android.os.IBinder; + +public final class AccountService extends Service { + + private Authenticator mAuthenticator; + + @Override + public void onCreate() { + mAuthenticator = new Authenticator(this); + } + + @Override + public IBinder onBind(Intent intent) { + return mAuthenticator.getIBinder(); + } +} diff --git a/src/com/university/journal/accounts/Authenticator.java b/src/com/university/journal/accounts/Authenticator.java new file mode 100644 index 0000000..f031b27 --- /dev/null +++ b/src/com/university/journal/accounts/Authenticator.java @@ -0,0 +1,110 @@ +package com.university.journal.accounts; + +import static com.university.journal.db.DbContract.AUTHORITY; +import com.university.journal.R; +import android.accounts.AbstractAccountAuthenticator; +import android.accounts.Account; +import android.accounts.AccountAuthenticatorResponse; +import android.accounts.AccountManager; +import android.accounts.NetworkErrorException; +import android.content.ContentResolver; +import android.content.Context; +import android.os.Bundle; + +public final class Authenticator extends AbstractAccountAuthenticator { + + private static final long SYNC_PERIOD = 24 * 60 * 60; + + public static final String AUTH_TOKEN_TYPE = "FULL"; + public static final String ACCOUNT_TYPE = "com.university.journal"; + + public static void addAccount(String login, AccountManager accountManager) { + final Account account = new Account(login, ACCOUNT_TYPE); + + accountManager.addAccountExplicitly(account, "password", null); + accountManager.setAuthToken(account, AUTH_TOKEN_TYPE, "token"); + + ContentResolver.setIsSyncable(account, AUTHORITY, 1); + ContentResolver.setSyncAutomatically(account, AUTHORITY, true); + ContentResolver.addPeriodicSync(account, AUTHORITY, new Bundle(), SYNC_PERIOD); + // Force sync + Bundle extras = new Bundle(); + extras.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true); + extras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true); + ContentResolver.requestSync(account, AUTHORITY, extras); + } + + private final Context mContext; + + public Authenticator(Context context) { + super(context); + this.mContext = context; + } + + @Override + public Bundle addAccount(AccountAuthenticatorResponse response, String accountType, String authTokenType, String[] requiredFeatures, Bundle options) + throws NetworkErrorException { + AccountManager accountManager = AccountManager.get(mContext); + Account[] accountsByType = accountManager.getAccountsByType(accountType); + final Bundle bundle = new Bundle(); + // Allow only one account + if (accountsByType.length > 0) { + bundle.putString(AccountManager.KEY_ERROR_MESSAGE, mContext.getString(R.string.one_account_allowed)); + return bundle; + } + + return null; + } + + @Override + public Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account, Bundle options) + throws NetworkErrorException { + return null; + } + + @Override + public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) { + return null; + } + + @Override + public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) + throws NetworkErrorException { + final Bundle bundle = new Bundle(); + if (!authTokenType.equals(AUTH_TOKEN_TYPE)) { + bundle.putString(AccountManager.KEY_ERROR_MESSAGE, "Invalid authTokenType"); + return bundle; + } + + final AccountManager am = AccountManager.get(mContext); + final String password = am.getPassword(account); + if (password != null) { + bundle.putString(AccountManager.KEY_ACCOUNT_NAME, account.name); + bundle.putString(AccountManager.KEY_ACCOUNT_TYPE, ACCOUNT_TYPE); + bundle.putString(AccountManager.KEY_AUTHTOKEN, account.name + "/" + password); + return bundle; + } + + return null; + } + + @Override + public String getAuthTokenLabel(String authTokenType) { + if (authTokenType.equals(AUTH_TOKEN_TYPE)) { + return mContext.getString(R.string.app_name); + } + return null; + } + + @Override + public Bundle hasFeatures(AccountAuthenticatorResponse response, Account account, String[] features) + throws NetworkErrorException { + return null; + } + + @Override + public Bundle updateCredentials(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) + throws NetworkErrorException { + return null; + } +} diff --git a/src/com/university/journal/db/ContentManager.java b/src/com/university/journal/db/ContentManager.java new file mode 100644 index 0000000..664762b --- /dev/null +++ b/src/com/university/journal/db/ContentManager.java @@ -0,0 +1,83 @@ +package com.university.journal.db; + +import java.util.ArrayList; +import java.util.List; +import android.content.ContentResolver; +import android.database.Cursor; +import com.university.journal.db.DbContract.Criteries; +import com.university.journal.db.DbContract.Marks; +import com.university.journal.db.DbContract.Students; +import com.university.journal.entity.Criteria; +import com.university.journal.entity.Mark; +import com.university.journal.entity.Student; + +public final class ContentManager { + + public static synchronized ContentManager with(ContentResolver cr) { + return new ContentManager(cr); + } + + private final ContentResolver mResolver; + + private ContentManager(ContentResolver resolver) { + this.mResolver = resolver; + } + + public List getCriteries(long subjectId) { + final String selection = Criteries.SUBJECT_ID + " = ?"; + final String[] args = { String.valueOf(subjectId) }; + Cursor cursor = mResolver.query( + Criteries.CONTENT_URI, Criteries.PROJECTION_ALL, + selection, args, Criteries.DATE); + List criteries = new ArrayList<>(); + if (cursor != null) { + while (cursor.moveToNext()) { + Criteria obj = new Criteria(); + obj.fromCursor(cursor); + criteries.add(obj); + } + } + if (cursor != null) { + cursor.close(); + } + return criteries; + } + + public List getStudents(long groupId) { + final String selection = Students.GROUP_ID + " = ?"; + final String[] args = { String.valueOf(groupId) }; + Cursor cursor = mResolver.query(Students.CONTENT_URI, null, + selection, args, Students.LAST_NAME); + ArrayList students = new ArrayList<>(); + if (cursor != null) { + while (cursor.moveToNext()) { + Student obj = new Student(); + obj.fromCursor(cursor); + obj.setId( cursor.getInt(cursor.getColumnIndex(Students._ID)) ); + students.add(obj); + } + } + if (cursor != null) { + cursor.close(); + } + return students; + } + + public Cursor getMarksCursor(long studentId) { + final String sel = Marks.STUDENT_ID + " = ?"; + final String[] args = { String.valueOf(studentId) }; + return mResolver.query(Marks.CONTENT_URI, null, sel, args, Marks.CRITERIA_ID); + } + + public void insertOrUpdate(Mark mark) { + final String where = String.format("%s = ? AND %s = ?", Marks.CRITERIA_ID, Marks.STUDENT_ID); + final String[] args = { + String.valueOf(mark.getCriteriaId()), + String.valueOf(mark.getStudentId()) + }; + int updateCount = mResolver.update(Marks.CONTENT_URI, mark.getContentValues(), where, args); + if (updateCount <= 0) { + mResolver.insert(Marks.CONTENT_URI, mark.getContentValues()); + } + } +} diff --git a/src/com/university/journal/db/DbContentProvider.java b/src/com/university/journal/db/DbContentProvider.java new file mode 100644 index 0000000..91c486a --- /dev/null +++ b/src/com/university/journal/db/DbContentProvider.java @@ -0,0 +1,313 @@ +package com.university.journal.db; + +import static com.university.journal.db.DbContract.*; +import android.content.ContentProvider; +import android.content.ContentUris; +import android.content.ContentValues; +import android.content.UriMatcher; +import android.database.Cursor; +import android.database.SQLException; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteQueryBuilder; +import android.net.Uri; +import android.text.TextUtils; + +public final class DbContentProvider extends ContentProvider { + + private static final UriMatcher URI_MATCHER = buildUriMatcher(); + private static final int STUDENTS_LIST = 10; + private static final int STUDENTS_ID = 11; + private static final int SUBJECTS_LIST = 20; + private static final int SUBJECTS_ID = 21; + private static final int GROUPS_LIST = 30; + private static final int GROUPS_ID = 31; + private static final int CRITERIES_LIST = 40; + private static final int CRITERIES_ID = 41; + private static final int MARKS_LIST = 50; + private static final int MARKS_ID = 51; + private static final int GROUP_BY_STUDENT = 91; + + private DbOpenHelper mDbHelper; + + private static final UriMatcher buildUriMatcher() { + final UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH); + matcher.addURI(DbContract.AUTHORITY, Students.TABLE_NAME, STUDENTS_LIST); + matcher.addURI(DbContract.AUTHORITY, Students.TABLE_NAME + "/#", STUDENTS_ID); + matcher.addURI(DbContract.AUTHORITY, Subjects.TABLE_NAME, SUBJECTS_LIST); + matcher.addURI(DbContract.AUTHORITY, Subjects.TABLE_NAME + "/#", SUBJECTS_ID); + matcher.addURI(DbContract.AUTHORITY, Groups.TABLE_NAME, GROUPS_LIST); + matcher.addURI(DbContract.AUTHORITY, Groups.TABLE_NAME + "/#", GROUPS_ID); + matcher.addURI(DbContract.AUTHORITY, Criteries.TABLE_NAME, CRITERIES_LIST); + matcher.addURI(DbContract.AUTHORITY, Criteries.TABLE_NAME + "/#", CRITERIES_ID); + matcher.addURI(DbContract.AUTHORITY, Marks.TABLE_NAME, MARKS_LIST); + matcher.addURI(DbContract.AUTHORITY, Marks.TABLE_NAME + "/#", MARKS_ID); + matcher.addURI(DbContract.AUTHORITY, "group_by_student", GROUP_BY_STUDENT); + return matcher; + } + + @Override + public boolean onCreate() { + mDbHelper = new DbOpenHelper(getContext()); + return true; + } + + @Override + public String getType(Uri uri) { + final int match = URI_MATCHER.match(uri); + switch (match) { + case STUDENTS_LIST: + return Students.CONTENT_TYPE; + case STUDENTS_ID: + return Students.CONTENT_ITEM_TYPE; + case SUBJECTS_LIST: + return Subjects.CONTENT_TYPE; + case SUBJECTS_ID: + return Subjects.CONTENT_ITEM_TYPE; + case GROUPS_LIST: + return Groups.CONTENT_TYPE; + case GROUPS_ID: + return Groups.CONTENT_ITEM_TYPE; + case CRITERIES_LIST: + return Criteries.CONTENT_TYPE; + case CRITERIES_ID: + return Criteries.CONTENT_ITEM_TYPE; + case MARKS_LIST: + return Marks.CONTENT_TYPE; + case MARKS_ID: + return Marks.CONTENT_ITEM_TYPE; + default: + throw new IllegalArgumentException("URI " + uri + " is not supported."); + } + } + + @Override + public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { + SQLiteDatabase db = mDbHelper.getReadableDatabase(); + SQLiteQueryBuilder builder = new SQLiteQueryBuilder(); + final int match = URI_MATCHER.match(uri); + switch (match) { + case STUDENTS_LIST: + builder.setTables(Students.TABLE_NAME); + break; + case STUDENTS_ID: + builder.setTables(Students.TABLE_NAME); + builder.appendWhere(Students._ID + " = " + uri.getLastPathSegment()); + break; + case SUBJECTS_LIST: + builder.setTables(Subjects.TABLE_NAME); + break; + case SUBJECTS_ID: + builder.setTables(Subjects.TABLE_NAME); + builder.appendWhere(Subjects._ID + " = " + uri.getLastPathSegment()); + break; + case GROUPS_LIST: + builder.setTables(Groups.TABLE_NAME); + break; + case GROUPS_ID: + builder.setTables(Groups.TABLE_NAME); + builder.appendWhere(Groups._ID + " = " + uri.getLastPathSegment()); + break; + case CRITERIES_LIST: + builder.setTables(Criteries.TABLE_NAME); + break; + case CRITERIES_ID: + builder.setTables(Criteries.TABLE_NAME); + builder.appendWhere(Criteries._ID + " = " + uri.getLastPathSegment()); + break; + case MARKS_LIST: + builder.setTables(Marks.TABLE_NAME); + break; + case MARKS_ID: + builder.setTables(Marks.TABLE_NAME); + builder.appendWhere(Marks._ID + " = " + uri.getLastPathSegment()); + break; + case GROUP_BY_STUDENT: + builder.setTables(String.format( + "%s INNER JOIN %s ON %s.%s = %s.%s", + Students.TABLE_NAME, Groups.TABLE_NAME, + Students.TABLE_NAME, Students.GROUP_ID, + Groups.TABLE_NAME, Groups._ID)); + projection = new String[] { + Groups.NAME, Students.GROUP_ID + }; + break; + default: + throw new IllegalArgumentException("URI " + uri + " is not supported."); + } + return builder.query(db, projection, selection, selectionArgs, null, null, sortOrder); + } + + @Override + public Uri insert(Uri uri, ContentValues values) { + SQLiteDatabase db = mDbHelper.getWritableDatabase(); + final int match = URI_MATCHER.match(uri); + switch(match){ + case STUDENTS_LIST: + long id = db.insert(Students.TABLE_NAME, null, values); + return getInsertedUri(id, uri); + case SUBJECTS_LIST: + id = db.insert(Subjects.TABLE_NAME, null, values); + return getInsertedUri(id, uri); + case GROUPS_LIST: + id = db.insert(Groups.TABLE_NAME, null, values); + return getInsertedUri(id, uri); + case CRITERIES_LIST: + id = db.insert(Criteries.TABLE_NAME, null, values); + return getInsertedUri(id, uri); + case MARKS_LIST: + id = db.insert(Marks.TABLE_NAME, null, values); + return getInsertedUri(id, uri); + default: + throw new IllegalArgumentException("URI " + uri + " is not supported."); + } + } + + private Uri getInsertedUri(long id, Uri uri) { + if (id <= 0) throw new SQLException("Problem while inserting into uri: " + uri); + Uri itemUri = ContentUris.withAppendedId(uri, id); + getContext().getContentResolver().notifyChange(itemUri, null); + return itemUri; + } + + @Override + public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { + SQLiteDatabase db = mDbHelper.getWritableDatabase(); + int updateCount = 0; + final int match = URI_MATCHER.match(uri); + switch (match) { + case STUDENTS_LIST: + updateCount = db.update(Students.TABLE_NAME, values, selection, selectionArgs); + break; + case STUDENTS_ID: + String where = Students._ID + " = " + uri.getLastPathSegment(); + if (!TextUtils.isEmpty(selection)) { + where += " AND " + selection; + } + updateCount = db.update(Students.TABLE_NAME, values, where, selectionArgs); + break; + + case SUBJECTS_LIST: + updateCount = db.update(Subjects.TABLE_NAME, values, selection, selectionArgs); + break; + case SUBJECTS_ID: + where = Subjects._ID + " = " + uri.getLastPathSegment(); + if (!TextUtils.isEmpty(selection)) { + where += " AND " + selection; + } + updateCount = db.update(Subjects.TABLE_NAME, values, where, selectionArgs); + break; + + case GROUPS_LIST: + updateCount = db.update(Groups.TABLE_NAME, values, selection, selectionArgs); + break; + case GROUPS_ID: + where = Groups._ID + " = " + uri.getLastPathSegment(); + if (!TextUtils.isEmpty(selection)) { + where += " AND " + selection; + } + updateCount = db.update(Groups.TABLE_NAME, values, where, selectionArgs); + break; + + case CRITERIES_LIST: + updateCount = db.update(Criteries.TABLE_NAME, values, selection, selectionArgs); + break; + case CRITERIES_ID: + where = Criteries._ID + " = " + uri.getLastPathSegment(); + if (!TextUtils.isEmpty(selection)) { + where += " AND " + selection; + } + updateCount = db.update(Criteries.TABLE_NAME, values, where, selectionArgs); + break; + + case MARKS_LIST: + updateCount = db.update(Marks.TABLE_NAME, values, selection, selectionArgs); + break; + case MARKS_ID: + where = Marks._ID + " = " + uri.getLastPathSegment(); + if (!TextUtils.isEmpty(selection)) { + where += " AND " + selection; + } + updateCount = db.update(Marks.TABLE_NAME, values, where, selectionArgs); + break; + + default: + throw new IllegalArgumentException("URI " + uri + " is not supported."); + } + if (updateCount > 0) { + getContext().getContentResolver().notifyChange(uri, null); + } + return updateCount; + } + + @Override + public int delete(Uri uri, String selection, String[] selectionArgs) { + SQLiteDatabase db = mDbHelper.getWritableDatabase(); + int deleteCount = 0; + final int match = URI_MATCHER.match(uri); + switch (match) { + case STUDENTS_LIST: + deleteCount = db.delete(Students.TABLE_NAME, selection, selectionArgs); + break; + case STUDENTS_ID: + String where = Students._ID + " = " + uri.getLastPathSegment(); + if (!TextUtils.isEmpty(selection)) { + where += " AND " + selection; + } + deleteCount = db.delete(Students.TABLE_NAME, where, selectionArgs); + break; + + case SUBJECTS_LIST: + deleteCount = db.delete(Subjects.TABLE_NAME, selection, selectionArgs); + break; + case SUBJECTS_ID: + where = Subjects._ID + " = " + uri.getLastPathSegment(); + if (!TextUtils.isEmpty(selection)) { + where += " AND " + selection; + } + deleteCount = db.delete(Subjects.TABLE_NAME, where, selectionArgs); + break; + + case GROUPS_LIST: + deleteCount = db.delete(Groups.TABLE_NAME, selection, selectionArgs); + break; + case GROUPS_ID: + where = Groups._ID + " = " + uri.getLastPathSegment(); + if (!TextUtils.isEmpty(selection)) { + where += " AND " + selection; + } + deleteCount = db.delete(Groups.TABLE_NAME, where, selectionArgs); + break; + + case CRITERIES_LIST: + deleteCount = db.delete(Criteries.TABLE_NAME, selection, selectionArgs); + break; + case CRITERIES_ID: + where = Criteries._ID + " = " + uri.getLastPathSegment(); + if (!TextUtils.isEmpty(selection)) { + where += " AND " + selection; + } + deleteCount = db.delete(Criteries.TABLE_NAME, where, selectionArgs); + break; + + case MARKS_LIST: + deleteCount = db.delete(Marks.TABLE_NAME, selection, selectionArgs); + break; + case MARKS_ID: + where = Marks._ID + " = " + uri.getLastPathSegment(); + if (!TextUtils.isEmpty(selection)) { + where += " AND " + selection; + } + deleteCount = db.delete(Marks.TABLE_NAME, where, selectionArgs); + break; + + default: + throw new IllegalArgumentException("URI " + uri + " is not supported."); + } + if (deleteCount > 0) { + getContext().getContentResolver().notifyChange(uri, null); + } + return deleteCount; + } + +} + diff --git a/src/com/university/journal/db/DbContract.java b/src/com/university/journal/db/DbContract.java new file mode 100644 index 0000000..0425254 --- /dev/null +++ b/src/com/university/journal/db/DbContract.java @@ -0,0 +1,103 @@ +package com.university.journal.db; + +import android.content.ContentResolver; +import android.net.Uri; +import android.provider.BaseColumns; + +public final class DbContract { + + public static final String AUTHORITY = "com.university.journal.dbprovider"; + + public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY); + + public static final class Students implements BaseColumns { + + public static final String TABLE_NAME = "students"; + + public static final Uri CONTENT_URI = Uri.withAppendedPath(DbContract.CONTENT_URI, TABLE_NAME); + + public static final String CONTENT_TYPE = ContentResolver.CURSOR_DIR_BASE_TYPE + "/vnd.com.university.journal." + TABLE_NAME; + + public static final String CONTENT_ITEM_TYPE = ContentResolver.CURSOR_ITEM_BASE_TYPE + "/vnd.com.university.journal." + TABLE_NAME; + + public static final String LAST_NAME = "lastname"; + + public static final String FIRST_NAME = "firstname"; + + public static final String MIDDLE_NAME = "midname"; + + public static final String GROUP_ID = "group_id"; + + public static final String[] PROJECTION_ALL = {_ID, LAST_NAME, FIRST_NAME, MIDDLE_NAME, GROUP_ID}; + } + + public static final class Subjects implements BaseColumns { + + public static final String TABLE_NAME = "subjects"; + + public static final Uri CONTENT_URI = Uri.withAppendedPath(DbContract.CONTENT_URI, TABLE_NAME); + + public static final String CONTENT_TYPE = ContentResolver.CURSOR_DIR_BASE_TYPE + "/vnd.com.university.journal." + TABLE_NAME; + + public static final String CONTENT_ITEM_TYPE = ContentResolver.CURSOR_ITEM_BASE_TYPE + "/vnd.com.university.journal." + TABLE_NAME; + + public static final String NAME = "_name"; + + public static final String SHORT_NAME = "shortname"; + + public static final String[] PROJECTION_ALL = {_ID, NAME, SHORT_NAME}; + } + + public static final class Groups implements BaseColumns { + + public static final String TABLE_NAME = "_groups"; + + public static final Uri CONTENT_URI = Uri.withAppendedPath(DbContract.CONTENT_URI, TABLE_NAME); + + public static final String CONTENT_TYPE = ContentResolver.CURSOR_DIR_BASE_TYPE + "/vnd.com.university.journal." + TABLE_NAME; + + public static final String CONTENT_ITEM_TYPE = ContentResolver.CURSOR_ITEM_BASE_TYPE + "/vnd.com.university.journal." + TABLE_NAME; + + public static final String NAME = "_name"; + + public static final String[] PROJECTION_ALL = {_ID, NAME}; + } + + public static final class Criteries implements BaseColumns { + + public static final String TABLE_NAME = "criteries"; + + public static final Uri CONTENT_URI = Uri.withAppendedPath(DbContract.CONTENT_URI, TABLE_NAME); + + public static final String CONTENT_TYPE = ContentResolver.CURSOR_DIR_BASE_TYPE + "/vnd.com.university.journal." + TABLE_NAME; + + public static final String CONTENT_ITEM_TYPE = ContentResolver.CURSOR_ITEM_BASE_TYPE + "/vnd.com.university.journal." + TABLE_NAME; + + public static final String SUBJECT_ID = "subject_id"; + + public static final String NAME = "_name"; + + public static final String DATE = "_date"; + + public static final String[] PROJECTION_ALL = {_ID, SUBJECT_ID, NAME, DATE}; + } + + public static final class Marks implements BaseColumns { + + public static final String TABLE_NAME = "marks"; + + public static final Uri CONTENT_URI = Uri.withAppendedPath(DbContract.CONTENT_URI, TABLE_NAME); + + public static final String CONTENT_TYPE = ContentResolver.CURSOR_DIR_BASE_TYPE + "/vnd.com.university.journal." + TABLE_NAME; + + public static final String CONTENT_ITEM_TYPE = ContentResolver.CURSOR_ITEM_BASE_TYPE + "/vnd.com.university.journal." + TABLE_NAME; + + public static final String STUDENT_ID = "student_id"; + + public static final String CRITERIA_ID = "criteria_id"; + + public static final String MARK = "mark"; + + public static final String[] PROJECTION_ALL = {_ID, STUDENT_ID, CRITERIA_ID, MARK}; + } +} diff --git a/src/com/university/journal/db/DbOpenHelper.java b/src/com/university/journal/db/DbOpenHelper.java new file mode 100644 index 0000000..2ae59d8 --- /dev/null +++ b/src/com/university/journal/db/DbOpenHelper.java @@ -0,0 +1,42 @@ +package com.university.journal.db; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; + +public final class DbOpenHelper extends SQLiteOpenHelper { + + private static final String NAME = DbSchema.DB_NAME; + private static final int VERSION = 1; + + public DbOpenHelper(Context context) { + super(context, NAME, null, VERSION); + } + + @Override + public void onCreate(SQLiteDatabase db) { + db.execSQL(DbSchema.DDL_CREATE_TBL_STUDENTS); + db.execSQL(DbSchema.DDL_CREATE_TBL_SUBJECTS); + db.execSQL(DbSchema.DDL_CREATE_TBL_GROUPS); + db.execSQL(DbSchema.DDL_CREATE_TBL_CRITERIES); + db.execSQL(DbSchema.DDL_CREATE_TBL_MARKS); + } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + db.execSQL(DbSchema.DDL_DROP_TBL_STUDENTS); + db.execSQL(DbSchema.DDL_DROP_TBL_SUBJECTS); + db.execSQL(DbSchema.DDL_DROP_TBL_GROUPS); + db.execSQL(DbSchema.DDL_DROP_TBL_CRITERIES); + db.execSQL(DbSchema.DDL_DROP_TBL_MARKS); + onCreate(db); + } + + @Override + public void onOpen(SQLiteDatabase db) { + super.onOpen(db); + if (!db.isReadOnly()) { + db.execSQL("PRAGMA foreign_keys=ON;"); + } + } +} diff --git a/src/com/university/journal/db/DbSchema.java b/src/com/university/journal/db/DbSchema.java new file mode 100644 index 0000000..72ee214 --- /dev/null +++ b/src/com/university/journal/db/DbSchema.java @@ -0,0 +1,56 @@ +package com.university.journal.db; + +import static com.university.journal.db.DbContract.*; + +public interface DbSchema { + + String DB_NAME = "journal.db"; + + String DDL_CREATE_TBL_STUDENTS = + "CREATE TABLE " + Students.TABLE_NAME + " (" + + Students._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, \n" + + Students.LAST_NAME + " TEXT NOT NULL, \n" + + Students.FIRST_NAME + " TEXT NOT NULL, \n" + + Students.MIDDLE_NAME + " TEXT NOT NULL, \n" + + Students.GROUP_ID + " INTEGER NOT NULL, \n" + + "FOREIGN KEY("+ Students.GROUP_ID + ") REFERENCES " + Groups.TABLE_NAME + "(" + Groups._ID + ") ON DELETE CASCADE \n" + + ")"; + + String DDL_CREATE_TBL_SUBJECTS = + "CREATE TABLE " + Subjects.TABLE_NAME + " (" + + Subjects._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, \n" + + Subjects.NAME + " TEXT NOT NULL, \n" + + Subjects.SHORT_NAME + " TEXT NOT NULL \n" + + ")"; + + String DDL_CREATE_TBL_GROUPS = + "CREATE TABLE " + Groups.TABLE_NAME + " (" + + Groups._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, \n" + + Groups.NAME + " TEXT NOT NULL \n" + + ")"; + + String DDL_CREATE_TBL_CRITERIES = + "CREATE TABLE " + Criteries.TABLE_NAME + " (" + + Criteries._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, \n" + + Criteries.SUBJECT_ID + " INTEGER NOT NULL, \n" + + Criteries.NAME + " TEXT NOT NULL, \n" + + Criteries.DATE + " TEXT NOT NULL, \n" + + "FOREIGN KEY("+ Criteries.SUBJECT_ID + ") REFERENCES " + Subjects.TABLE_NAME + "(" + Subjects._ID + ") ON DELETE CASCADE \n" + + ")"; + + String DDL_CREATE_TBL_MARKS = + "CREATE TABLE " + Marks.TABLE_NAME + " (" + + Marks._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, \n" + + Marks.STUDENT_ID + " INTEGER NOT NULL, \n" + + Marks.CRITERIA_ID + " INTEGER NOT NULL, \n" + + Marks.MARK + " TEXT NOT NULL, \n" + + "FOREIGN KEY("+ Marks.STUDENT_ID + ") REFERENCES " + Students.TABLE_NAME + "(" + Students._ID + ") ON DELETE CASCADE, \n" + + "FOREIGN KEY("+ Marks.CRITERIA_ID + ") REFERENCES " + Criteries.TABLE_NAME + "(" + Criteries._ID + ") ON DELETE CASCADE \n" + + ")"; + + String DDL_DROP_TBL_STUDENTS = "DROP TABLE IF EXISTS " + Students.TABLE_NAME; + String DDL_DROP_TBL_SUBJECTS = "DROP TABLE IF EXISTS " + Subjects.TABLE_NAME; + String DDL_DROP_TBL_GROUPS = "DROP TABLE IF EXISTS " + Groups.TABLE_NAME; + String DDL_DROP_TBL_CRITERIES = "DROP TABLE IF EXISTS " + Criteries.TABLE_NAME; + String DDL_DROP_TBL_MARKS = "DROP TABLE IF EXISTS " + Marks.TABLE_NAME; +} diff --git a/src/com/university/journal/entity/Criteria.java b/src/com/university/journal/entity/Criteria.java new file mode 100644 index 0000000..8843571 --- /dev/null +++ b/src/com/university/journal/entity/Criteria.java @@ -0,0 +1,77 @@ +package com.university.journal.entity; + +import com.university.journal.db.DbContract.Criteries; +import android.content.ContentValues; +import android.database.Cursor; +import android.provider.BaseColumns; + +public final class Criteria implements DatabaseSerializer { + + private int id; + private int subjectId; + private String name; + private String date; + + public Criteria() { } + + public Criteria(String name, String date, int subjectId) { + this.name = name; + this.date = date; + this.subjectId = subjectId; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public int getSubjectId() { + return subjectId; + } + + public void setSubjectId(int subjectId) { + this.subjectId = subjectId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDate() { + return date; + } + + public void setDate(String date) { + this.date = date; + } + + @Override + public void fromCursor(Cursor cursor) { + id = cursor.getInt(cursor.getColumnIndex(BaseColumns._ID)); + subjectId = cursor.getInt(cursor.getColumnIndex(Criteries.SUBJECT_ID)); + name = cursor.getString(cursor.getColumnIndex(Criteries.NAME)); + date = cursor.getString(cursor.getColumnIndex(Criteries.DATE)); + } + + @Override + public ContentValues getContentValues() { + ContentValues cv = new ContentValues(); + cv.put(Criteries.NAME, name); + cv.put(Criteries.DATE, date); + cv.put(Criteries.SUBJECT_ID, subjectId); + return cv; + } + + public String readableString() { + return name + "\n" + date; + } + + +} diff --git a/src/com/university/journal/entity/DatabaseSerializer.java b/src/com/university/journal/entity/DatabaseSerializer.java new file mode 100644 index 0000000..d3045db --- /dev/null +++ b/src/com/university/journal/entity/DatabaseSerializer.java @@ -0,0 +1,11 @@ +package com.university.journal.entity; + +import android.content.ContentValues; +import android.database.Cursor; + +public interface DatabaseSerializer { + + void fromCursor(Cursor cursor); + + ContentValues getContentValues(); +} diff --git a/src/com/university/journal/entity/Group.java b/src/com/university/journal/entity/Group.java new file mode 100644 index 0000000..92d66e9 --- /dev/null +++ b/src/com/university/journal/entity/Group.java @@ -0,0 +1,47 @@ +package com.university.journal.entity; + +import com.university.journal.db.DbContract.Groups; +import android.content.ContentValues; +import android.database.Cursor; +import android.provider.BaseColumns; + +public final class Group implements DatabaseSerializer { + + private int id; + private String name; + + public Group() { } + + public Group(String name) { + this.name = name; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public void fromCursor(Cursor cursor) { + id = cursor.getInt(cursor.getColumnIndex(BaseColumns._ID)); + name = cursor.getString(cursor.getColumnIndex(Groups.NAME)); + } + + @Override + public ContentValues getContentValues() { + ContentValues cv = new ContentValues(); + cv.put(Groups.NAME, name); + return cv; + } +} diff --git a/src/com/university/journal/entity/Mark.java b/src/com/university/journal/entity/Mark.java new file mode 100644 index 0000000..ae09f4b --- /dev/null +++ b/src/com/university/journal/entity/Mark.java @@ -0,0 +1,70 @@ +package com.university.journal.entity; + +import com.university.journal.db.DbContract.Marks; +import android.content.ContentValues; +import android.database.Cursor; +import android.provider.BaseColumns; + +public final class Mark implements DatabaseSerializer { + + private int id; + private int studentId, criteriaId; + private String mark; + + public Mark() { } + + public Mark(int studentId, int criteriaId, String mark) { + this.studentId = studentId; + this.criteriaId = criteriaId; + this.mark = mark; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public int getStudentId() { + return studentId; + } + + public void setStudentId(int studentId) { + this.studentId = studentId; + } + + public int getCriteriaId() { + return criteriaId; + } + + public void setCriteriaId(int criteriaId) { + this.criteriaId = criteriaId; + } + + public String getMark() { + return mark; + } + + public void setMark(String mark) { + this.mark = mark; + } + + @Override + public void fromCursor(Cursor cursor) { + id = cursor.getInt(cursor.getColumnIndex(BaseColumns._ID)); + studentId = cursor.getInt(cursor.getColumnIndex(Marks.STUDENT_ID)); + criteriaId = cursor.getInt(cursor.getColumnIndex(Marks.CRITERIA_ID)); + mark = cursor.getString(cursor.getColumnIndex(Marks.MARK)); + } + + @Override + public ContentValues getContentValues() { + ContentValues cv = new ContentValues(); + cv.put(Marks.STUDENT_ID, studentId); + cv.put(Marks.CRITERIA_ID, criteriaId); + cv.put(Marks.MARK, mark); + return cv; + } +} diff --git a/src/com/university/journal/entity/MarksTableItem.java b/src/com/university/journal/entity/MarksTableItem.java new file mode 100644 index 0000000..b18e158 --- /dev/null +++ b/src/com/university/journal/entity/MarksTableItem.java @@ -0,0 +1,24 @@ +package com.university.journal.entity; + +public final class MarksTableItem { + + private Student student; + private Mark[] marks; + + public MarksTableItem(Student student, Mark[] marks) { + this.student = student; + this.marks = marks; + } + + public Student getStudent() { + return student; + } + + public Mark getMark(int index) { + return marks[index]; + } + + public void setMark(int index, Mark mark) { + marks[index] = mark; + } +} \ No newline at end of file diff --git a/src/com/university/journal/entity/Student.java b/src/com/university/journal/entity/Student.java new file mode 100644 index 0000000..2c2ff1e --- /dev/null +++ b/src/com/university/journal/entity/Student.java @@ -0,0 +1,83 @@ +package com.university.journal.entity; + +import com.university.journal.db.DbContract.Students; +import android.content.ContentValues; +import android.database.Cursor; + +public final class Student implements DatabaseSerializer { + + private int id; + private String firstName, lastName, middleName; + private int groupId; + + public Student() { } + + public Student(String firstName, String lastName, String middleName, int groupId) { + this.firstName = firstName; + this.lastName = lastName; + this.middleName = middleName; + this.groupId = groupId; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public String getMiddleName() { + return middleName; + } + + public void setMiddleName(String middleName) { + this.middleName = middleName; + } + + public int getGroupId() { + return groupId; + } + + public void setGroupId(int groupId) { + this.groupId = groupId; + } + + @Override + public void fromCursor(Cursor cursor) { + firstName = cursor.getString(cursor.getColumnIndex(Students.FIRST_NAME)); + lastName = cursor.getString(cursor.getColumnIndex(Students.LAST_NAME)); + middleName = cursor.getString(cursor.getColumnIndex(Students.MIDDLE_NAME)); + groupId = cursor.getInt(cursor.getColumnIndex(Students.GROUP_ID)); + } + + @Override + public ContentValues getContentValues() { + ContentValues cv = new ContentValues(); + cv.put(Students.FIRST_NAME, firstName); + cv.put(Students.LAST_NAME, lastName); + cv.put(Students.MIDDLE_NAME, middleName); + cv.put(Students.GROUP_ID, groupId); + return cv; + } + + public String readableString() { + return String.format("%s %c.%c.", lastName, firstName.charAt(0), middleName.charAt(0)); + } +} \ No newline at end of file diff --git a/src/com/university/journal/entity/Subject.java b/src/com/university/journal/entity/Subject.java new file mode 100644 index 0000000..438b666 --- /dev/null +++ b/src/com/university/journal/entity/Subject.java @@ -0,0 +1,58 @@ +package com.university.journal.entity; + +import static com.university.journal.db.DbContract.Subjects; +import android.content.ContentValues; +import android.database.Cursor; +import android.provider.BaseColumns; + +public final class Subject implements DatabaseSerializer { + + private int id; + private String name, shortName; + + public Subject() {} + + public Subject(String name, String shortName) { + this.name = name; + this.shortName = shortName; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getShortName() { + return shortName; + } + + public void setShortName(String shortName) { + this.shortName = shortName; + } + + @Override + public void fromCursor(Cursor cursor) { + id = cursor.getInt(cursor.getColumnIndex(BaseColumns._ID)); + name = cursor.getString(cursor.getColumnIndex(Subjects.NAME)); + shortName = cursor.getString(cursor.getColumnIndex(Subjects.SHORT_NAME)); + } + + @Override + public ContentValues getContentValues() { + ContentValues cv = new ContentValues(); + cv.put(Subjects.NAME, name); + cv.put(Subjects.SHORT_NAME, shortName); + return cv; + } +} diff --git a/src/com/university/journal/fragments/CriteriaFragment.java b/src/com/university/journal/fragments/CriteriaFragment.java new file mode 100644 index 0000000..26b72c2 --- /dev/null +++ b/src/com/university/journal/fragments/CriteriaFragment.java @@ -0,0 +1,62 @@ +package com.university.journal.fragments; + +import android.content.ContentUris; +import android.database.Cursor; +import android.os.Bundle; +import android.support.v4.app.DialogFragment; +import android.support.v4.content.CursorLoader; +import android.support.v4.content.Loader; +import com.university.journal.db.DbContract.Criteries; +import com.university.journal.entity.Criteria; + +public final class CriteriaFragment extends DbTableFragment { + + @Override + protected int loaderNumber() { + return 3; + } + + @Override + protected String[] getUIBindFrom() { + return new String[] { Criteries.NAME, Criteries.DATE }; + } + + @Override + protected int[] getUIBindTo() { + return new int[] { android.R.id.text1, android.R.id.text2 }; + } + + @Override + protected int getUIBindLayoutResource() { + return android.R.layout.simple_list_item_2; + } + + @Override + protected DialogFragment getAddDataDialogFragment() { + return NewCriteriaDialogFragment.newInstance(mListener); + } + + @Override + protected void onItemDelete(long id) { + getActivity().getContentResolver() + .delete(ContentUris.withAppendedId(Criteries.CONTENT_URI, id), null, null); + } + + @Override + public Loader onCreateLoader(int id, Bundle bundle) { + return new CursorLoader(getActivity(), + Criteries.CONTENT_URI, Criteries.PROJECTION_ALL, + null, null, null); + } + + private NewCriteriaDialogFragment.AddListener mListener = new NewCriteriaDialogFragment.AddListener() { + + @Override + public void onConfirm(String name, String date, long subjectId) { + Criteria obj = new Criteria(name, date, (int) subjectId); + getActivity().getContentResolver() + .insert(Criteries.CONTENT_URI, obj.getContentValues()); + getActivity().getSupportLoaderManager().getLoader(loaderNumber()).forceLoad(); + } + }; +} diff --git a/src/com/university/journal/fragments/DbTableFragment.java b/src/com/university/journal/fragments/DbTableFragment.java new file mode 100644 index 0000000..05be682 --- /dev/null +++ b/src/com/university/journal/fragments/DbTableFragment.java @@ -0,0 +1,146 @@ +package com.university.journal.fragments; + +import android.database.Cursor; +import android.os.Bundle; +import android.support.v4.app.DialogFragment; +import android.support.v4.app.FragmentTransaction; +import android.support.v4.app.ListFragment; +import android.support.v4.app.LoaderManager.LoaderCallbacks; +import android.support.v4.content.Loader; +import android.support.v4.widget.SimpleCursorAdapter; +import android.support.v7.app.ActionBarActivity; +import android.support.v7.view.ActionMode; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.widget.AdapterView; +import com.university.journal.R; + +public abstract class DbTableFragment extends ListFragment implements LoaderCallbacks { + + private long mSelectedId; + private SimpleCursorAdapter mAdapter; + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + setHasOptionsMenu(true); + + final String[] from = getUIBindFrom(); + final int[] to = getUIBindTo(); + + mAdapter = new SimpleCursorAdapter(getActivity(), + getUIBindLayoutResource(), null, + from, to, + SimpleCursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER); + postInitAdapter(mAdapter); + setListAdapter(mAdapter); + setEmptyText(getString(R.string.no_data)); + + getListView().setOnItemLongClickListener(mItemLongClickListener); + getActivity().getSupportLoaderManager().initLoader(loaderNumber(), null, this); + } + + protected abstract String[] getUIBindFrom(); + + protected int[] getUIBindTo() { + return new int[] { android.R.id.text1 }; + } + + protected int getUIBindLayoutResource() { + return android.R.layout.simple_list_item_1; + } + + protected void postInitAdapter(SimpleCursorAdapter adapter) { } + + protected abstract int loaderNumber(); + + protected abstract DialogFragment getAddDataDialogFragment(); + + protected abstract void onItemDelete(long id); + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + inflater.inflate(R.menu.add_item, menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.action_add: + FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction(); + getAddDataDialogFragment().show(ft, "dialog"); + return true; + } + return false; + } + + @Override + public void onLoadFinished(Loader loader, Cursor cursor) { + if (mAdapter != null) { + mAdapter.swapCursor(cursor); + } + if (isResumed()) { + setListShown(true); + } else { + setListShownNoAnimation(true); + } + } + + @Override + public void onLoaderReset(Loader loader) { + if (mAdapter != null) { + mAdapter.swapCursor(null); + } + } + + private final AdapterView.OnItemLongClickListener mItemLongClickListener = + new AdapterView.OnItemLongClickListener() { + + @Override + public boolean onItemLongClick(AdapterView parent, View view, int position, long id) { + mSelectedId = id; + ((ActionBarActivity) getActivity()).startSupportActionMode(mActionCallback); + return true; + } + + }; + + private final ActionMode.Callback mActionCallback = new ActionMode.Callback() { + + @Override + public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) { + // Similar to menu handling in Activity.onOptionsItemSelected() + switch (menuItem.getItemId()) { + case R.id.action_delete: + // Some remove functionality + onItemDelete(mSelectedId); + getActivity().getSupportLoaderManager().getLoader(loaderNumber()).forceLoad(); + actionMode.finish(); + return true; + } + + return false; + } + + @Override + public boolean onCreateActionMode(ActionMode actionMode, Menu menu) { + // Inflate our menu from a resource file + actionMode.getMenuInflater().inflate(R.menu.item_context, menu); + + // Return true so that the action mode is shown + return true; + } + + @Override + public void onDestroyActionMode(ActionMode actionMode) { + // Allows you to be notified when the action mode is dismissed + } + + @Override + public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) { + return false; + } + }; +} diff --git a/src/com/university/journal/fragments/GroupFragment.java b/src/com/university/journal/fragments/GroupFragment.java new file mode 100644 index 0000000..7a84363 --- /dev/null +++ b/src/com/university/journal/fragments/GroupFragment.java @@ -0,0 +1,51 @@ +package com.university.journal.fragments; + +import android.content.ContentUris; +import android.database.Cursor; +import android.os.Bundle; +import android.support.v4.app.DialogFragment; +import android.support.v4.content.CursorLoader; +import android.support.v4.content.Loader; +import com.university.journal.db.DbContract.Groups; +import com.university.journal.entity.Group; + +public final class GroupFragment extends DbTableFragment { + + @Override + protected int loaderNumber() { + return 1; + } + + @Override + protected String[] getUIBindFrom() { + return new String[] { Groups.NAME }; + } + + @Override + protected DialogFragment getAddDataDialogFragment() { + return NewGroupDialogFragment.newInstance(mListener); + } + + @Override + protected void onItemDelete(long id) { + getActivity().getContentResolver() + .delete(ContentUris.withAppendedId(Groups.CONTENT_URI, id), null, null); + } + + @Override + public Loader onCreateLoader(int id, Bundle bundle) { + return new CursorLoader(getActivity(), + Groups.CONTENT_URI, Groups.PROJECTION_ALL, + null, null, null); + } + + private NewGroupDialogFragment.AddListener mListener = new NewGroupDialogFragment.AddListener() { + + @Override + public void onConfirm(String name) { + Group obj = new Group(name); + getActivity().getContentResolver().insert(Groups.CONTENT_URI, obj.getContentValues()); + getActivity().getSupportLoaderManager().getLoader(loaderNumber()).forceLoad(); + } + }; +} diff --git a/src/com/university/journal/fragments/MainFragment.java b/src/com/university/journal/fragments/MainFragment.java new file mode 100644 index 0000000..d13fc86 --- /dev/null +++ b/src/com/university/journal/fragments/MainFragment.java @@ -0,0 +1,244 @@ +package com.university.journal.fragments; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.nio.charset.Charset; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; +import android.database.Cursor; +import android.os.Bundle; +import android.os.Environment; +import android.support.v4.app.DialogFragment; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentTransaction; +import android.support.v4.widget.SimpleCursorAdapter; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.Spinner; +import android.widget.Toast; +import com.inqbarna.tablefixheaders.TableFixHeaders; +import com.inqbarna.tablefixheaders.adapters.TableAdapter; +import com.university.journal.EmptyTableAdapter; +import com.university.journal.MarksTableAdapter; +import com.university.journal.R; +import com.university.journal.db.ContentManager; +import com.university.journal.db.DbContract.Groups; +import com.university.journal.db.DbContract.Subjects; +import com.university.journal.entity.Criteria; +import com.university.journal.entity.Mark; +import com.university.journal.entity.MarksTableItem; +import com.university.journal.entity.Student; + +public final class MainFragment extends Fragment { + + private static TableAdapter sEmptyAdapter; + + private Spinner mSubjectSpinner, mGroupSpinner; + private TableFixHeaders mTable; + private MarksTableAdapter mAdapter; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_main, container, false); + setHasOptionsMenu(true); + + mSubjectSpinner = (Spinner) view.findViewById(R.id.subjectSpinner); + mGroupSpinner = (Spinner) view.findViewById(R.id.groupSpinner); + mTable = (TableFixHeaders) view.findViewById(R.id.table); + + Cursor cur = getActivity().getContentResolver() + .query(Subjects.CONTENT_URI, Subjects.PROJECTION_ALL, null, null, null); + String[] from = new String[] { Subjects.NAME }; + int[] to = new int[] { android.R.id.text1 }; + SimpleCursorAdapter adapter = new SimpleCursorAdapter(getActivity(), + android.R.layout.simple_spinner_item, cur, + from, to, SimpleCursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER); + adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + mSubjectSpinner.setAdapter(adapter); + mSubjectSpinner.setOnItemSelectedListener(mSpinnerListener); + + cur = getActivity().getContentResolver() + .query(Groups.CONTENT_URI, Groups.PROJECTION_ALL, null, null, null); + from = new String[] { Groups.NAME }; + to = new int[] { android.R.id.text1 }; + adapter = new SimpleCursorAdapter(getActivity(), + android.R.layout.simple_spinner_item, cur, + from, to, SimpleCursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER); + adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + mGroupSpinner.setAdapter(adapter); + mGroupSpinner.setOnItemSelectedListener(mSpinnerListener); + + sEmptyAdapter = new EmptyTableAdapter(getActivity()); + mTable.setAdapter(sEmptyAdapter); + return view; + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + inflater.inflate(R.menu.main, menu); + super.onCreateOptionsMenu(menu, inflater); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.action_export: + export(); + return true; + } + return super.onOptionsItemSelected(item); + } + + private void export() { + if (mAdapter == null) return; + + final String SEP = ",", NEWLINE = "\r\n"; + StringBuilder csv = new StringBuilder(); + // For correctly open in Excel + csv.append("sep=").append(SEP).append(NEWLINE); + // Headers + csv.append("").append(SEP); + for (int i = 0; i < mAdapter.getColumnCount(); i++) { + Criteria cr = mAdapter.getHeader(i); + String header = cr.getName() + " / " + cr.getDate();// cr.readableString(); + csv.append(header).append(SEP); + } + csv.append(NEWLINE); + // Data + for (int i = 0; i < mAdapter.getRowCount(); i++) { + MarksTableItem item = mAdapter.getItem(i); + csv.append(item.getStudent().readableString()).append(SEP); + for (int j = 0; j < mAdapter.getColumnCount(); j++) { + csv.append(item.getMark(j).getMark()).append(SEP); + } + csv.append(NEWLINE); + } + + // Save to sdcard + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd_HH_mm_ss"); + String fullPath = Environment.getExternalStorageDirectory() + + File.separator + sdf.format(new Date()) + ".csv"; + try { + Charset charset = Charset.isSupported("CP1251") + ? Charset.forName("CP1251") : Charset.defaultCharset(); + FileOutputStream out = new FileOutputStream(new File(fullPath)); + OutputStreamWriter writer = new OutputStreamWriter(out, charset); + writer.write(csv.toString()); + writer.flush(); + writer.close(); + Toast.makeText(getActivity(), + getString(R.string.saved) + " " + fullPath, + Toast.LENGTH_SHORT).show(); + } catch (IOException ioe) { + ioe.printStackTrace(); + } + } + + private void showTable() { + long subjectId = mSubjectSpinner.getSelectedItemId(); + if (subjectId == AdapterView.INVALID_ROW_ID) return; + + long groupId = mGroupSpinner.getSelectedItemId(); + if (groupId == AdapterView.INVALID_ROW_ID) return; + + // Get criteries + List criteries = ContentManager + .with(getActivity().getContentResolver()) + .getCriteries(subjectId); + if (criteries.isEmpty()) return; + final Criteria[] headers = criteries.toArray(new Criteria[0]); + + // Get students + List students = ContentManager + .with(getActivity().getContentResolver()) + .getStudents(groupId); + + // Get marks + MarksTableItem[] items = new MarksTableItem[students.size()]; + for (int i = 0; i < items.length; i++) { + final Student student = students.get(i); + final int studentId = student.getId(); + Mark[] marks = new Mark[headers.length]; + for (int j = 0; j < headers.length; j++) { + marks[j] = new Mark(studentId, headers[j].getId(), ""); + } + + Cursor cursor = ContentManager + .with(getActivity().getContentResolver()) + .getMarksCursor(studentId); + if (cursor != null) { + while (cursor.moveToNext()) { + Mark obj = new Mark(); + obj.fromCursor(cursor); + for (int j = 0; j < headers.length; j++) { + if (headers[j].getId() == obj.getId()) { + marks[j] = obj; + break; + } + } + } + } + items[i] = new MarksTableItem(student, marks); + } + mAdapter = new MarksTableAdapter(getActivity(), headers, items); + mAdapter.setMarkClickListener(mMarksButtonListener); + mTable.setAdapter(mAdapter); + } + + private final View.OnClickListener mMarksButtonListener = + new View.OnClickListener() { + + @Override + public void onClick(View v) { + final int column = (int) v.getTag(R.id.tag_column); + final int row = (int) v.getTag(R.id.tag_row); + + final Mark mark = mAdapter.getItem(row).getMark(column); + DialogFragment frag = NewMarkDialogFragment.newInstance(mAddListener, + mark.getCriteriaId(), mark.getStudentId(), mark.getMark(), + row, column); + + FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction(); + frag.show(ft, "dialog"); + } + }; + + private NewMarkDialogFragment.AddListener mAddListener = new NewMarkDialogFragment.AddListener() { + + @Override + public void onConfirm(int row, int column, Mark mark) { + ContentManager.with(getActivity().getContentResolver()) + .insertOrUpdate(mark); + mAdapter.getItem(row).setMark(column, mark); + mAdapter.notifyDataSetChanged(); + } + }; + + private final AdapterView.OnItemSelectedListener mSpinnerListener = + new AdapterView.OnItemSelectedListener() { + + @Override + public void onItemSelected(AdapterView parent, View view, int position, long id) { + showTable(); + boolean empty = (mTable.getAdapter() == null) || + (mTable.getAdapter().getColumnCount() == 0); + if (empty) { + mTable.setAdapter(sEmptyAdapter); + } + } + + @Override + public void onNothingSelected(AdapterView parent) { + mTable.setAdapter(sEmptyAdapter); + } + }; + +} \ No newline at end of file diff --git a/src/com/university/journal/fragments/NewCriteriaDialogFragment.java b/src/com/university/journal/fragments/NewCriteriaDialogFragment.java new file mode 100644 index 0000000..fda3a67 --- /dev/null +++ b/src/com/university/journal/fragments/NewCriteriaDialogFragment.java @@ -0,0 +1,77 @@ +package com.university.journal.fragments; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Locale; +import android.database.Cursor; +import android.support.v4.widget.SimpleCursorAdapter; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.EditText; +import android.widget.Spinner; +import com.university.journal.R; +import com.university.journal.db.DbContract.Subjects; + +public final class NewCriteriaDialogFragment extends NewItemDialogFragment { + + public interface AddListener { + void onConfirm(String name, String date, long subjectId); + }; + + private AddListener mListener; + private EditText mNameEditText, mDateEditText; + private Spinner subjectSpinner; + private SimpleCursorAdapter mSpinnerAdapter; + + public static NewCriteriaDialogFragment newInstance(AddListener listener) { + NewCriteriaDialogFragment frag = new NewCriteriaDialogFragment(); + frag.mListener = listener; + frag.setCancelable(false); + return frag; + } + + @Override + protected View inflate(LayoutInflater inflater) { + View view = inflater.inflate(R.layout.dialog_add_criteria, null, false); + mNameEditText = (EditText) view.findViewById(R.id.name); + mDateEditText = (EditText) view.findViewById(R.id.date); + subjectSpinner = (Spinner) view.findViewById(R.id.subjectSpinner); + + final Cursor cur = getActivity().getContentResolver() + .query(Subjects.CONTENT_URI, Subjects.PROJECTION_ALL, null, null, null); + final String[] from = new String[] { Subjects.NAME }; + final int[] to = new int[] { android.R.id.text1 }; + mSpinnerAdapter = new SimpleCursorAdapter(getActivity(), + android.R.layout.simple_spinner_item, cur, + from, to, SimpleCursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER); + mSpinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + subjectSpinner.setAdapter(mSpinnerAdapter); + return view; + } + + @Override + protected boolean validate() { + if (mNameEditText == null) return false; + final String name = mNameEditText.getText().toString(); + if (TextUtils.isEmpty(name)) return false; + + if (mDateEditText == null) return false; + final String date = mDateEditText.getText().toString(); + if (TextUtils.isEmpty(date)) return false; + try { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd", Locale.US); + sdf.setLenient(false); + sdf.parse(date); + } catch (ParseException ex) { + return false; + } + + if (subjectSpinner.getSelectedItem() == null) return false; + + if (mListener != null) { + mListener.onConfirm(name, date, subjectSpinner.getSelectedItemId()); + } + return true; + } +} diff --git a/src/com/university/journal/fragments/NewGroupDialogFragment.java b/src/com/university/journal/fragments/NewGroupDialogFragment.java new file mode 100644 index 0000000..18ce8a3 --- /dev/null +++ b/src/com/university/journal/fragments/NewGroupDialogFragment.java @@ -0,0 +1,43 @@ +package com.university.journal.fragments; + +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.EditText; +import com.university.journal.R; + +public final class NewGroupDialogFragment extends NewItemDialogFragment { + + public interface AddListener { + void onConfirm(String name); + }; + + private AddListener mListener; + private EditText mNameEditText; + + public static NewGroupDialogFragment newInstance(AddListener listener) { + NewGroupDialogFragment frag = new NewGroupDialogFragment(); + frag.mListener = listener; + frag.setCancelable(false); + return frag; + } + + @Override + protected View inflate(LayoutInflater inflater) { + View view = inflater.inflate(R.layout.dialog_add_group, null, false); + mNameEditText = (EditText) view.findViewById(R.id.name); + return view; + } + + @Override + protected boolean validate() { + if (mNameEditText == null) return false; + final String name = mNameEditText.getText().toString(); + if (TextUtils.isEmpty(name)) return false; + + if (mListener != null) { + mListener.onConfirm(name); + } + return true; + } +} diff --git a/src/com/university/journal/fragments/NewItemDialogFragment.java b/src/com/university/journal/fragments/NewItemDialogFragment.java new file mode 100644 index 0000000..7f5e676 --- /dev/null +++ b/src/com/university/journal/fragments/NewItemDialogFragment.java @@ -0,0 +1,51 @@ +package com.university.journal.fragments; + +import android.app.AlertDialog; +import android.app.Dialog; +import android.os.Bundle; +import android.support.v4.app.DialogFragment; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.Toast; +import com.university.journal.R; + +public abstract class NewItemDialogFragment extends DialogFragment { + + protected abstract View inflate(LayoutInflater inflater); + + protected abstract boolean validate(); + + @Override + public void onStart() { + super.onStart(); + final AlertDialog dialog = (AlertDialog) getDialog(); + if (dialog != null) { + dialog.getButton(Dialog.BUTTON_POSITIVE) + .setOnClickListener(new View.OnClickListener() { + + @Override + public void onClick(View v) { + if (validate()) { + dismiss(); + } else { + Toast.makeText(getActivity(), + getString(R.string.validate_error), + Toast.LENGTH_SHORT).show(); + } + } + }); + } + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + View view = inflate(LayoutInflater.from(getActivity())); + + final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + builder.setView(view); + builder.setTitle(R.string.add); + builder.setPositiveButton(android.R.string.ok, null); + builder.setNegativeButton(android.R.string.cancel, null); + return builder.create(); + } +} diff --git a/src/com/university/journal/fragments/NewMarkDialogFragment.java b/src/com/university/journal/fragments/NewMarkDialogFragment.java new file mode 100644 index 0000000..63a45cb --- /dev/null +++ b/src/com/university/journal/fragments/NewMarkDialogFragment.java @@ -0,0 +1,79 @@ +package com.university.journal.fragments; + +import android.os.Bundle; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.EditText; +import com.university.journal.R; +import com.university.journal.entity.Mark; + +public final class NewMarkDialogFragment extends NewItemDialogFragment { + + private static final String ARG_MARK_VALUE = "mark", + ARG_CRITERIA_ID = "criteria_id", + ARG_STUDENT_ID = "student_id", + ARG_TABLE_ROW = "table_row", + ARG_TABLE_COL = "table_col"; + + public interface AddListener { + void onConfirm(int row, int col, Mark mark); + }; + + private AddListener mListener; + private EditText mMarkEditText; + private Mark mMark; + private int mRow, mCol; + + public static NewMarkDialogFragment newInstance(AddListener listener, + int criteriaId, int studentId, String markValue, + int row, int col) { + NewMarkDialogFragment frag = new NewMarkDialogFragment(); + frag.mListener = listener; + frag.setCancelable(false); + + final Bundle args = new Bundle(); + args.putString(ARG_MARK_VALUE, markValue); + args.putInt(ARG_CRITERIA_ID, criteriaId); + args.putInt(ARG_STUDENT_ID, studentId); + args.putInt(ARG_TABLE_ROW, row); + args.putInt(ARG_TABLE_COL, col); + frag.setArguments(args); + return frag; + } + + @Override + protected View inflate(LayoutInflater inflater) { + View view = inflater.inflate(R.layout.dialog_add_mark, null, false); + mMarkEditText = (EditText) view.findViewById(R.id.mark); + + mMark = new Mark(); + final Bundle args = getArguments(); + if (args != null) { + final String markValue = args.getString(ARG_MARK_VALUE); + mMark.setMark(markValue); + mMark.setCriteriaId(args.getInt(ARG_CRITERIA_ID)); + mMark.setStudentId(args.getInt(ARG_STUDENT_ID)); + mRow = args.getInt(ARG_TABLE_ROW); + mCol = args.getInt(ARG_TABLE_COL); + mMarkEditText.setText(markValue); + } + return view; + } + + @Override + protected boolean validate() { + if (mMarkEditText == null) return false; + final String markValue = mMarkEditText.getText().toString(); + if (TextUtils.isEmpty(markValue)) return false; + + // No edit mark - not update. + if (mMark.getMark().equals(markValue)) return true; + mMark.setMark(markValue); + + if (mListener != null) { + mListener.onConfirm(mRow, mCol, mMark); + } + return true; + } +} diff --git a/src/com/university/journal/fragments/NewStudentDialogFragment.java b/src/com/university/journal/fragments/NewStudentDialogFragment.java new file mode 100644 index 0000000..683ebab --- /dev/null +++ b/src/com/university/journal/fragments/NewStudentDialogFragment.java @@ -0,0 +1,72 @@ +package com.university.journal.fragments; + +import android.database.Cursor; +import android.support.v4.widget.SimpleCursorAdapter; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.EditText; +import android.widget.Spinner; +import com.university.journal.R; +import com.university.journal.db.DbContract.Groups; + +public final class NewStudentDialogFragment extends NewItemDialogFragment { + + public interface AddListener { + void onConfirm(String firstName, String lastName, String middleName, long groupId); + }; + + private AddListener mListener; + private EditText mFirtsNameEditText, mLastNameEditText, mMiddleNameEditText; + private Spinner mGroupSpinner; + private SimpleCursorAdapter mSpinnerAdapter; + + public static NewStudentDialogFragment newInstance(AddListener listener) { + NewStudentDialogFragment frag = new NewStudentDialogFragment(); + frag.mListener = listener; + frag.setCancelable(false); + return frag; + } + + @Override + protected View inflate(LayoutInflater inflater) { + View view = inflater.inflate(R.layout.dialog_add_student, null, false); + mFirtsNameEditText = (EditText) view.findViewById(R.id.firstname); + mLastNameEditText = (EditText) view.findViewById(R.id.lastname); + mMiddleNameEditText = (EditText) view.findViewById(R.id.middlename); + mGroupSpinner = (Spinner) view.findViewById(R.id.groupSpinner); + + final Cursor cur = getActivity().getContentResolver() + .query(Groups.CONTENT_URI, Groups.PROJECTION_ALL, null, null, null); + final String[] from = new String[] { Groups.NAME }; + final int[] to = new int[] { android.R.id.text1 }; + mSpinnerAdapter = new SimpleCursorAdapter(getActivity(), + android.R.layout.simple_spinner_item, cur, + from, to, SimpleCursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER); + mSpinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + mGroupSpinner.setAdapter(mSpinnerAdapter); + return view; + } + + @Override + protected boolean validate() { + if (mFirtsNameEditText == null) return false; + final String firstName = mFirtsNameEditText.getText().toString(); + if (TextUtils.isEmpty(firstName)) return false; + + if (mLastNameEditText == null) return false; + final String lastName = mLastNameEditText.getText().toString(); + if (TextUtils.isEmpty(lastName)) return false; + + if (mMiddleNameEditText == null) return false; + final String middleName = mMiddleNameEditText.getText().toString(); + if (TextUtils.isEmpty(middleName)) return false; + + if (mGroupSpinner.getSelectedItem() == null) return false; + + if (mListener != null) { + mListener.onConfirm(firstName, lastName, middleName, mGroupSpinner.getSelectedItemId()); + } + return true; + } +} diff --git a/src/com/university/journal/fragments/NewSubjectDialogFragment.java b/src/com/university/journal/fragments/NewSubjectDialogFragment.java new file mode 100644 index 0000000..4437585 --- /dev/null +++ b/src/com/university/journal/fragments/NewSubjectDialogFragment.java @@ -0,0 +1,48 @@ +package com.university.journal.fragments; + +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.EditText; +import com.university.journal.R; + +public final class NewSubjectDialogFragment extends NewItemDialogFragment { + + public interface AddListener { + void onConfirm(String name, String shortName); + }; + + private AddListener mListener; + private EditText mNameEditText, mShortNameEditText; + + public static NewSubjectDialogFragment newInstance(AddListener listener) { + NewSubjectDialogFragment frag = new NewSubjectDialogFragment(); + frag.mListener = listener; + frag.setCancelable(false); + return frag; + } + + @Override + protected View inflate(LayoutInflater inflater) { + View view = inflater.inflate(R.layout.dialog_add_subject, null, false); + mNameEditText = (EditText) view.findViewById(R.id.name); + mShortNameEditText = (EditText) view.findViewById(R.id.shortName); + return view; + } + + @Override + protected boolean validate() { + if (mNameEditText == null) return false; + final String name = mNameEditText.getText().toString(); + if (TextUtils.isEmpty(name)) return false; + + if (mShortNameEditText == null) return false; + final String shortName = mShortNameEditText.getText().toString(); + if (TextUtils.isEmpty(shortName)) return false; + + if (mListener != null) { + mListener.onConfirm(name, shortName); + } + return true; + } +} diff --git a/src/com/university/journal/fragments/StudentFragment.java b/src/com/university/journal/fragments/StudentFragment.java new file mode 100644 index 0000000..691728b --- /dev/null +++ b/src/com/university/journal/fragments/StudentFragment.java @@ -0,0 +1,105 @@ +package com.university.journal.fragments; + +import android.content.ContentUris; +import android.database.Cursor; +import android.net.Uri; +import android.os.Bundle; +import android.support.v4.app.DialogFragment; +import android.support.v4.content.CursorLoader; +import android.support.v4.content.Loader; +import android.support.v4.widget.SimpleCursorAdapter; +import android.view.View; +import android.widget.AdapterView; +import android.widget.TextView; +import android.widget.Toast; +import com.university.journal.db.DbContract; +import com.university.journal.db.DbContract.Groups; +import com.university.journal.db.DbContract.Students; +import com.university.journal.entity.Student; + +public final class StudentFragment extends DbTableFragment { + + @Override + protected int loaderNumber() { + return 2; + } + + @Override + protected String[] getUIBindFrom() { + return new String[] { Students.LAST_NAME, Students.FIRST_NAME, Students.MIDDLE_NAME }; + } + + @Override + protected int[] getUIBindTo() { + return new int[] { android.R.id.text1 }; + } + + @Override + protected int getUIBindLayoutResource() { + return android.R.layout.simple_list_item_1; + } + + @Override + protected void postInitAdapter(SimpleCursorAdapter adapter) { + adapter.setViewBinder(new SimpleCursorAdapter.ViewBinder() { + + @Override + public boolean setViewValue(View view, Cursor cursor, int columnIndex) { + final String lastName = cursor.getString(1); + final String firstName = cursor.getString(2); + final String middleName = cursor.getString(3); + TextView textView = (TextView) view; + textView.setText(String.format("%s %s %s", + lastName, firstName, middleName)); + return true; + } + }); + getListView().setOnItemClickListener(mItemClickListener); + } + + @Override + protected DialogFragment getAddDataDialogFragment() { + return NewStudentDialogFragment.newInstance(mListener); + } + + @Override + protected void onItemDelete(long id) { + getActivity().getContentResolver() + .delete(ContentUris.withAppendedId(Students.CONTENT_URI, id), null, null); + } + + @Override + public Loader onCreateLoader(int id, Bundle bundle) { + return new CursorLoader(getActivity(), + Students.CONTENT_URI, Students.PROJECTION_ALL, + null, null, Students.LAST_NAME); + } + + private final AdapterView.OnItemClickListener mItemClickListener = + new AdapterView.OnItemClickListener() { + + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + String selection = String.format("%s.%s = ?", Students.TABLE_NAME, Students._ID); + String[] args = { String.valueOf(id) }; + Cursor cursor = getActivity().getContentResolver() + .query(Uri.withAppendedPath(DbContract.CONTENT_URI, "group_by_student"), + null, selection, args, null); + if ( (cursor != null) && (cursor.moveToFirst()) ) { + String group = cursor.getString(cursor.getColumnIndex(Groups.NAME)); + Toast.makeText(getActivity(), group, Toast.LENGTH_SHORT).show(); + } + } + }; + + private NewStudentDialogFragment.AddListener mListener = new NewStudentDialogFragment.AddListener() { + + @Override + public void onConfirm(String firstName, String lastName, String middleName, long groupId) { + Student obj = new Student(firstName, lastName, middleName, (int) groupId); + getActivity().getContentResolver() + .insert(Students.CONTENT_URI, obj.getContentValues()); + getActivity().getSupportLoaderManager().getLoader(loaderNumber()).forceLoad(); + } + }; +} diff --git a/src/com/university/journal/fragments/SubjectFragment.java b/src/com/university/journal/fragments/SubjectFragment.java new file mode 100644 index 0000000..7636b60 --- /dev/null +++ b/src/com/university/journal/fragments/SubjectFragment.java @@ -0,0 +1,51 @@ +package com.university.journal.fragments; + +import android.content.ContentUris; +import android.database.Cursor; +import android.os.Bundle; +import android.support.v4.app.DialogFragment; +import android.support.v4.content.CursorLoader; +import android.support.v4.content.Loader; +import com.university.journal.db.DbContract.Subjects; +import com.university.journal.entity.Subject; + +public final class SubjectFragment extends DbTableFragment { + + @Override + protected int loaderNumber() { + return 0; + } + + @Override + protected String[] getUIBindFrom() { + return new String[] { Subjects.NAME }; + } + + @Override + protected DialogFragment getAddDataDialogFragment() { + return NewSubjectDialogFragment.newInstance(mListener); + } + + @Override + protected void onItemDelete(long id) { + getActivity().getContentResolver() + .delete(ContentUris.withAppendedId(Subjects.CONTENT_URI, id), null, null); + } + + @Override + public Loader onCreateLoader(int id, Bundle bundle) { + return new CursorLoader(getActivity(), + Subjects.CONTENT_URI, Subjects.PROJECTION_ALL, + null, null, null); + } + + private NewSubjectDialogFragment.AddListener mListener = new NewSubjectDialogFragment.AddListener() { + + @Override + public void onConfirm(String name, String shortName) { + Subject obj = new Subject(name, shortName); + getActivity().getContentResolver().insert(Subjects.CONTENT_URI, obj.getContentValues()); + getActivity().getSupportLoaderManager().getLoader(loaderNumber()).forceLoad(); + } + }; +}