├── .gitignore ├── .idea ├── codeStyles │ └── Project.xml ├── gradle.xml ├── jarRepositories.xml ├── misc.xml ├── render.experimental.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── remcv │ │ └── com │ │ └── github │ │ └── examprep │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── ic_launcher-playstore.png │ ├── java │ │ └── remcv │ │ │ └── com │ │ │ └── github │ │ │ └── examprep │ │ │ ├── AddExamItemActivity.java │ │ │ ├── MainActivity.java │ │ │ ├── TestSubjectsActivity.java │ │ │ ├── UpdateDeleteItemActivity.java │ │ │ ├── controller │ │ │ ├── DatabaseCrud.java │ │ │ └── DatabaseHandler.java │ │ │ ├── model │ │ │ └── ExamItem.java │ │ │ ├── utils │ │ │ ├── TableConstants.java │ │ │ └── Utils.java │ │ │ └── view │ │ │ ├── DialogNumberOfQuestions.java │ │ │ ├── ExamItemAdapter.java │ │ │ └── MyDialogDatePicker.java │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ ├── check_icon.png │ │ ├── circle.xml │ │ ├── circle2.xml │ │ ├── circle_subject_solved.xml │ │ ├── classroom.jpg │ │ ├── ic_baseline_add_24.xml │ │ ├── ic_baseline_notes_24.xml │ │ ├── ic_launcher_background.xml │ │ ├── mountains.jpg │ │ └── pencil.jpg │ │ ├── layout │ │ ├── activity_add_exam_item.xml │ │ ├── activity_main.xml │ │ ├── activity_test_subjects.xml │ │ ├── activity_update_delete_item.xml │ │ ├── dialog_number_of_questions.xml │ │ ├── exam_item.xml │ │ └── exam_item_test.xml │ │ ├── menu │ │ └── settings_menu.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── remcv │ └── com │ └── github │ └── examprep │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── screenshots └── Screenshot_03.jpg └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 20 | 21 | 22 | 23 | 25 | 26 | 27 |
28 | 29 | 30 | 31 | xmlns:android 32 | 33 | ^$ 34 | 35 | 36 | 37 |
38 |
39 | 40 | 41 | 42 | xmlns:.* 43 | 44 | ^$ 45 | 46 | 47 | BY_NAME 48 | 49 |
50 |
51 | 52 | 53 | 54 | .*:id 55 | 56 | http://schemas.android.com/apk/res/android 57 | 58 | 59 | 60 |
61 |
62 | 63 | 64 | 65 | .*:name 66 | 67 | http://schemas.android.com/apk/res/android 68 | 69 | 70 | 71 |
72 |
73 | 74 | 75 | 76 | name 77 | 78 | ^$ 79 | 80 | 81 | 82 |
83 |
84 | 85 | 86 | 87 | style 88 | 89 | ^$ 90 | 91 | 92 | 93 |
94 |
95 | 96 | 97 | 98 | .* 99 | 100 | ^$ 101 | 102 | 103 | BY_NAME 104 | 105 |
106 |
107 | 108 | 109 | 110 | .* 111 | 112 | http://schemas.android.com/apk/res/android 113 | 114 | 115 | ANDROID_ATTRIBUTE_ORDER 116 | 117 |
118 |
119 | 120 | 121 | 122 | .* 123 | 124 | .* 125 | 126 | 127 | BY_NAME 128 | 129 |
130 |
131 |
132 |
133 |
134 |
-------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | -------------------------------------------------------------------------------- /.idea/render.experimental.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ExamPrep 2 | 3 | Simple Android application to help you prepare for your exams. 4 | 5 | ### How it works 6 | Randomly select a predefined number of questions from a list of questions. 7 | 8 | ### Features 9 | - add, update, delete exam items 10 | - countdown of the number of days until your exam (can be modified by the user) 11 | - the user can check and exclude the problems already solved 12 | - upload your own list of questions in .tsv format (number\tsubject\tisSolved) from your Android phone 13 | - test yourself with a user-determined number of random questions 14 | 15 | ### Screenshot 16 | 17 | ![App screenshot](/screenshots/Screenshot_03.jpg) 18 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 29 5 | buildToolsVersion "29.0.3" 6 | 7 | defaultConfig { 8 | applicationId "remcv.com.github.examprep" 9 | minSdkVersion 28 10 | targetSdkVersion 29 11 | versionCode 1 12 | versionName "1.0" 13 | 14 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 15 | } 16 | 17 | buildTypes { 18 | release { 19 | minifyEnabled false 20 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 21 | } 22 | } 23 | compileOptions { 24 | sourceCompatibility JavaVersion.VERSION_1_8 25 | targetCompatibility JavaVersion.VERSION_1_8 26 | } 27 | } 28 | 29 | dependencies { 30 | implementation fileTree(dir: "libs", include: ["*.jar"]) 31 | implementation 'androidx.appcompat:appcompat:1.1.0' 32 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3' 33 | implementation 'com.google.android.material:material:1.1.0' 34 | testImplementation 'junit:junit:4.12' 35 | androidTestImplementation 'androidx.test.ext:junit:1.1.1' 36 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' 37 | implementation 'com.google.code.gson:gson:2.8.6' 38 | } -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /app/src/androidTest/java/remcv/com/github/examprep/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package remcv.com.github.examprep; 2 | 3 | import android.content.Context; 4 | 5 | import androidx.test.platform.app.InstrumentationRegistry; 6 | import androidx.test.ext.junit.runners.AndroidJUnit4; 7 | 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | 11 | import static org.junit.Assert.*; 12 | 13 | /** 14 | * Instrumented test, which will execute on an Android device. 15 | * 16 | * @see Testing documentation 17 | */ 18 | @RunWith(AndroidJUnit4.class) 19 | public class ExampleInstrumentedTest 20 | { 21 | @Test 22 | public void useAppContext() 23 | { 24 | // Context of the app under test. 25 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); 26 | assertEquals("remcv.com.github.examprep", appContext.getPackageName()); 27 | } 28 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 14 | 15 | 18 | 19 | 23 | 24 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /app/src/main/ic_launcher-playstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remcv/ExamPrep-Android/da0fbe255c73bb2d2a1a5605c2152b8ddbd4a0f5/app/src/main/ic_launcher-playstore.png -------------------------------------------------------------------------------- /app/src/main/java/remcv/com/github/examprep/AddExamItemActivity.java: -------------------------------------------------------------------------------- 1 | package remcv.com.github.examprep; 2 | 3 | import androidx.appcompat.app.AppCompatActivity; 4 | 5 | import android.content.Intent; 6 | import android.os.Bundle; 7 | import android.util.Log; 8 | import android.widget.Button; 9 | import android.widget.CheckBox; 10 | 11 | import com.google.android.material.textfield.TextInputLayout; 12 | 13 | import remcv.com.github.examprep.utils.TableConstants; 14 | import remcv.com.github.examprep.utils.Utils; 15 | 16 | public class AddExamItemActivity extends AppCompatActivity 17 | { 18 | // fields - data 19 | public static final String TAG = "ExamPrep"; 20 | 21 | // fields - layout 22 | private TextInputLayout categoryNumber_TIL; 23 | private TextInputLayout problem_TIL; 24 | private Button addItem_Button; 25 | private CheckBox subjectIsSolved_CB; 26 | 27 | // methods - lifecycle 28 | @Override 29 | protected void onCreate(Bundle savedInstanceState) 30 | { 31 | super.onCreate(savedInstanceState); 32 | setContentView(R.layout.activity_add_exam_item); 33 | 34 | // initialize data 35 | 36 | // initialize layout 37 | initializeLayout(); 38 | 39 | // handle button events 40 | addItem_Button.setOnClickListener((v) -> onAddItemButtonClicked()); 41 | } 42 | 43 | // methods - handle button clicks 44 | public void onAddItemButtonClicked() 45 | { 46 | // check input data validity 47 | if (Utils.isNumberValid(categoryNumber_TIL) & Utils.isStringInputValid(problem_TIL)) 48 | { 49 | int categoryNumber = Integer.parseInt(categoryNumber_TIL.getEditText().getText().toString()); 50 | String problem = problem_TIL.getEditText().getText().toString(); 51 | boolean isDone = subjectIsSolved_CB.isChecked(); 52 | 53 | Log.d(TAG, "onAddItemButtonClicked: isDone before - " + isDone); 54 | 55 | Intent intent = new Intent(AddExamItemActivity.this, MainActivity.class); 56 | intent.putExtra(TableConstants.CATEGORY_NUMBER, categoryNumber); 57 | intent.putExtra(TableConstants.PROBLEM, problem); 58 | intent.putExtra(TableConstants.IS_DONE, isDone); 59 | 60 | // set result to pass to MainActivity 61 | setResult(RESULT_OK, intent); 62 | 63 | // finish current activity without starting a new MainActivity 64 | finish(); 65 | } 66 | } 67 | 68 | // methods - data 69 | public void initializeData() 70 | { 71 | // TODO 72 | } 73 | 74 | // methods layout 75 | public void initializeLayout() 76 | { 77 | categoryNumber_TIL = findViewById(R.id.categoryNumberTextInputLayout_AAEI); 78 | problem_TIL = findViewById(R.id.problemTextInputLayout_AAEI); 79 | addItem_Button = findViewById(R.id.addItemButton_AAEI); 80 | subjectIsSolved_CB = findViewById(R.id.subjectSolvedCheckBox_AAEI); 81 | } 82 | } -------------------------------------------------------------------------------- /app/src/main/java/remcv/com/github/examprep/MainActivity.java: -------------------------------------------------------------------------------- 1 | package remcv.com.github.examprep; 2 | 3 | import androidx.annotation.NonNull; 4 | import androidx.annotation.Nullable; 5 | import androidx.appcompat.app.AppCompatActivity; 6 | 7 | import android.app.DatePickerDialog; 8 | import android.content.Intent; 9 | import android.content.SharedPreferences; 10 | import android.net.Uri; 11 | import android.os.Bundle; 12 | import android.util.Log; 13 | import android.view.Menu; 14 | import android.view.MenuInflater; 15 | import android.view.MenuItem; 16 | import android.widget.DatePicker; 17 | import android.widget.ListView; 18 | import android.widget.TextView; 19 | import android.widget.Toast; 20 | 21 | import com.google.gson.Gson; 22 | 23 | import java.io.BufferedReader; 24 | import java.io.File; 25 | import java.io.IOException; 26 | import java.io.InputStream; 27 | import java.io.InputStreamReader; 28 | import java.time.LocalDate; 29 | import java.time.Month; 30 | import java.util.Collections; 31 | import java.util.List; 32 | import java.util.stream.Collectors; 33 | 34 | import remcv.com.github.examprep.controller.DatabaseCrud; 35 | import remcv.com.github.examprep.controller.DatabaseHandler; 36 | import remcv.com.github.examprep.model.ExamItem; 37 | import remcv.com.github.examprep.utils.TableConstants; 38 | import remcv.com.github.examprep.utils.Utils; 39 | import remcv.com.github.examprep.view.DialogNumberOfQuestions; 40 | import remcv.com.github.examprep.view.ExamItemAdapter; 41 | import remcv.com.github.examprep.view.MyDialogDatePicker; 42 | 43 | public class MainActivity extends AppCompatActivity implements TableConstants, DialogNumberOfQuestions.DialogNumberOfQuestionsListener, DatePickerDialog.OnDateSetListener 44 | { 45 | // fields - data 46 | private File sourceFile; 47 | private DatabaseCrud databaseHandler; 48 | private ExamItemAdapter adapter; 49 | private int numberOfSubjectsToTest; 50 | private int solvedNumberOfSubjects; 51 | private LocalDate examDate; 52 | 53 | // fields - static final 54 | private static final String TAG = "ExamPrep"; 55 | private static final int ADD_ITEM_REQUEST_CODE = 1; 56 | private static final int UPDATE_DELETE_ITEM_REQUEST_CODE = 2; 57 | private static final int UPLOAD_TSV_REQUEST_CODE = 3; 58 | public static final String SHARED_PREFS = "mySharedPrefs"; 59 | public static final String NUMBER_OF_SUBJECTS = "numberOfSubjects"; 60 | public static final String EXAM_YEAR = "examYear"; 61 | public static final String EXAM_MONTH = "examMonth"; 62 | public static final String EXAM_DAY = "examDay"; 63 | 64 | // fields - layout 65 | private TextView countdown_TV; 66 | private TextView numberOfSubjects_TV; 67 | private TextView totalNumberOfSubjects_TV; 68 | private ListView problems_LV; 69 | 70 | // methods - lifecycle 71 | @Override 72 | protected void onCreate(Bundle savedInstanceState) 73 | { 74 | super.onCreate(savedInstanceState); 75 | setContentView(R.layout.activity_main); 76 | 77 | // initialize data 78 | initializeData(); 79 | 80 | // initiate layout 81 | initializeLayout(); 82 | 83 | // ListView adapter 84 | adapter = new ExamItemAdapter(databaseHandler.getList(), MainActivity.this); 85 | problems_LV.setAdapter(adapter); 86 | 87 | // handle events 88 | problems_LV.setOnItemClickListener((parent, view, position, id) -> onListViewItemClicked(position)); 89 | } 90 | 91 | @Override 92 | protected void onStop() 93 | { 94 | super.onStop(); 95 | 96 | // save database 97 | databaseHandler.saveDb(sourceFile); 98 | } 99 | 100 | @Override 101 | protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) 102 | { 103 | super.onActivityResult(requestCode, resultCode, data); 104 | 105 | /* 106 | 1 - add item 107 | 2 - update OR delete 108 | 3 - import database from tsv file 109 | */ 110 | 111 | if (resultCode == RESULT_OK) 112 | { 113 | switch (requestCode) 114 | { 115 | case ADD_ITEM_REQUEST_CODE: 116 | onAddItemReturn(data); 117 | break; 118 | case UPDATE_DELETE_ITEM_REQUEST_CODE: 119 | onUpdateDeleteReturn(data); 120 | break; 121 | case UPLOAD_TSV_REQUEST_CODE: 122 | onUploadReturn(data); 123 | break; 124 | } 125 | } 126 | 127 | Collections.sort(databaseHandler.getList()); 128 | adapter.notifyDataSetChanged(); 129 | 130 | updateData(); 131 | updateUI(); 132 | } 133 | 134 | // methods - handle events 135 | public void onListViewItemClicked(int position) 136 | { 137 | ExamItem examItem = databaseHandler.getList().get(position); 138 | 139 | Intent intent = new Intent(MainActivity.this, UpdateDeleteItemActivity.class); 140 | intent.putExtra(TableConstants.CATEGORY_NUMBER, examItem.getCategoryNumber()); 141 | intent.putExtra(TableConstants.PROBLEM, examItem.getProblem()); 142 | intent.putExtra(TableConstants.IS_DONE, examItem.getIsDone()); 143 | intent.putExtra(TableConstants.INDEX, position); 144 | 145 | int requestCode = 2; 146 | startActivityForResult(intent, requestCode); 147 | } 148 | 149 | @Override 150 | public boolean onOptionsItemSelected(@NonNull MenuItem item) 151 | { 152 | switch (item.getItemId()) 153 | { 154 | case R.id.settingsMenu_itemAdd: 155 | onAddButtonClicked(); 156 | break; 157 | case R.id.settingsMenu_itemGenerateRandomList: 158 | onGenerateRandomListOfSubjectsClicked(); 159 | break; 160 | case R.id.settingsMenu_itemChangeExamDate: 161 | onChangeExamDateMenuItemClicked(); 162 | break; 163 | case R.id.settingsMenu_itemSetNoSubjectsInTest: 164 | createAlertDialogNumberOfQuestions(); 165 | break; 166 | case R.id.settingsMenu_itemImport: 167 | onImportButtonClicked(); 168 | break; 169 | } 170 | 171 | return true; 172 | } 173 | 174 | public void onAddButtonClicked() 175 | { 176 | Intent addIntent = new Intent(MainActivity.this, AddExamItemActivity.class); 177 | startActivityForResult(addIntent, ADD_ITEM_REQUEST_CODE); 178 | } 179 | 180 | public void onGenerateRandomListOfSubjectsClicked() 181 | { 182 | List list = databaseHandler.getList().stream() 183 | .filter(examItem -> !examItem.getIsDone()) 184 | .collect(Collectors.toList()); 185 | 186 | list = Utils.generateRandomSubjectList(numberOfSubjectsToTest, list); 187 | 188 | if (list == null) 189 | { 190 | Toast.makeText(this, "Not enough subjects or categories in your list", Toast.LENGTH_SHORT).show(); 191 | } 192 | else 193 | { 194 | // send the list to TestSubjectsActivity 195 | Gson gson = new Gson(); 196 | String listJson = gson.toJson(list); 197 | 198 | Intent toTestSubjectsActivityIntent = new Intent(MainActivity.this, TestSubjectsActivity.class); 199 | toTestSubjectsActivityIntent.putExtra(TableConstants.RANDOM_LIST, listJson); 200 | 201 | startActivity(toTestSubjectsActivityIntent); 202 | } 203 | } 204 | 205 | public void onImportButtonClicked() 206 | { 207 | // create Intent to open an external csv file 208 | Intent getCsvIntent = new Intent(Intent.ACTION_OPEN_DOCUMENT); 209 | getCsvIntent.addCategory(Intent.CATEGORY_OPENABLE); 210 | getCsvIntent.setType("text/tab-separated-values"); 211 | 212 | startActivityForResult(getCsvIntent, UPLOAD_TSV_REQUEST_CODE); 213 | } 214 | 215 | // methods - data 216 | public void initializeData() 217 | { 218 | // instantiate a DatabaseCrud implementation 219 | databaseHandler = new DatabaseHandler(MainActivity.this); 220 | 221 | // instantiate the database File object by accessing the Android device app storage 222 | sourceFile = new File(getApplicationContext().getFilesDir(), databaseHandler.getDatabasePath()); 223 | 224 | // create the .csv file if it doesn't exist (for first time users) 225 | try 226 | { 227 | sourceFile.createNewFile(); 228 | } 229 | catch (IOException e) 230 | { 231 | Log.e(TAG, "initializeData() " + e.getMessage()); 232 | } 233 | 234 | // load the database from storage 235 | databaseHandler.loadDb(sourceFile); 236 | Collections.sort(databaseHandler.getList()); 237 | 238 | // calculate solvedNumberOfSubjects 239 | solvedNumberOfSubjects = (int) databaseHandler.getList().stream() 240 | .filter(ExamItem::getIsDone) 241 | .count(); 242 | 243 | // load the number of subjects (default value is 5) 244 | numberOfSubjectsToTest = getSharedPreferences(SHARED_PREFS, MODE_PRIVATE).getInt(NUMBER_OF_SUBJECTS, 5); 245 | 246 | // load exam date 247 | int year = getSharedPreferences(SHARED_PREFS, MODE_PRIVATE).getInt(EXAM_YEAR, 0); 248 | int month = getSharedPreferences(SHARED_PREFS, MODE_PRIVATE).getInt(EXAM_MONTH, 0); 249 | int dayOfMonth = getSharedPreferences(SHARED_PREFS, MODE_PRIVATE).getInt(EXAM_DAY, 0); 250 | 251 | if (year == 0) 252 | { 253 | // default value of exam date is 30 days from the current day 254 | examDate = LocalDate.now().plusDays(30); 255 | } 256 | else 257 | { 258 | examDate = LocalDate.of(year, month, dayOfMonth); 259 | } 260 | } 261 | 262 | public void updateData() 263 | { 264 | solvedNumberOfSubjects = (int) databaseHandler.getList().stream() 265 | .filter(ExamItem::getIsDone) 266 | .count(); 267 | } 268 | 269 | public void onAddItemReturn(Intent data) 270 | { 271 | int categoryNumber = data.getIntExtra(TableConstants.CATEGORY_NUMBER, 0); 272 | String problem = data.getStringExtra(TableConstants.PROBLEM); 273 | boolean isDone = data.getBooleanExtra(TableConstants.IS_DONE, false); 274 | 275 | ExamItem newExamItem = new ExamItem(categoryNumber, problem, isDone); 276 | databaseHandler.getList().add(newExamItem); 277 | 278 | Toast.makeText(this, "Exam item added", Toast.LENGTH_SHORT).show(); 279 | } 280 | 281 | public void onUpdateDeleteReturn(Intent data) 282 | { 283 | // get metadata 284 | String buttonName = data.getStringExtra(TableConstants.BUTTON_NAME); 285 | int index = data.getIntExtra(TableConstants.INDEX, 0); 286 | 287 | if (buttonName.equals("deleteButton")) 288 | { 289 | onDeleteReturn(index); 290 | } 291 | else // buttonName.equals("updateButton") 292 | { 293 | onUpdateReturn(index, data); 294 | } 295 | } 296 | 297 | public void onDeleteReturn(int index) 298 | { 299 | databaseHandler.getList().remove(index); 300 | Toast.makeText(MainActivity.this, "Item deleted", Toast.LENGTH_SHORT).show(); 301 | } 302 | 303 | public void onUpdateReturn(int index, Intent data) 304 | { 305 | // gather data 306 | int categoryNumber = data.getIntExtra(TableConstants.CATEGORY_NUMBER, -1); 307 | String problem = data.getStringExtra(TableConstants.PROBLEM); 308 | boolean isDone = data.getBooleanExtra(TableConstants.IS_DONE, false); 309 | 310 | // create ExamItem and update it in list 311 | databaseHandler.getList().set(index, new ExamItem(categoryNumber, problem, isDone)); 312 | } 313 | 314 | public void onDeleteItem(int index) 315 | { 316 | databaseHandler.getList().remove(index); 317 | Toast.makeText(this, "Exam item deleted", Toast.LENGTH_SHORT).show(); 318 | } 319 | 320 | public void onUploadReturn(Intent data) 321 | { 322 | Uri csvUri = data.getData(); 323 | InputStream inputStream = null; 324 | 325 | try 326 | { 327 | inputStream = getContentResolver().openInputStream(csvUri); 328 | BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); 329 | 330 | // if no exception was thrown until here, then clear the old list 331 | databaseHandler.getList().clear(); 332 | 333 | String line; 334 | String[] lineArray; 335 | 336 | while ((line = reader.readLine()) != null) 337 | { 338 | lineArray = line.split("\t", 3); 339 | int categoryNumber = Integer.parseInt(lineArray[0]); 340 | String problem = lineArray[1]; 341 | boolean isDone = Boolean.parseBoolean(lineArray[2]); 342 | 343 | ExamItem item = new ExamItem(categoryNumber, problem, isDone); 344 | databaseHandler.getList().add(item); 345 | } 346 | 347 | reader.close(); 348 | inputStream.close(); 349 | 350 | // update data and UI 351 | solvedNumberOfSubjects = (int) databaseHandler.getList().stream() 352 | .filter(ExamItem::getIsDone) 353 | .count(); 354 | totalNumberOfSubjects_TV.setText(String.format("Subjects (%d)", databaseHandler.getList().size())); 355 | } 356 | catch (Exception e) 357 | { 358 | Log.d(TAG, "onUploadReturn: exception " + e.getMessage()); 359 | Toast.makeText(this, "File loading failed", Toast.LENGTH_SHORT).show(); 360 | } 361 | } 362 | 363 | // methods layout 364 | public void initializeLayout() 365 | { 366 | countdown_TV = findViewById(R.id.countdownTextView_AM); 367 | numberOfSubjects_TV = findViewById(R.id.numberOfSubjects_AM); 368 | problems_LV = findViewById(R.id.problemsListView_AM); 369 | totalNumberOfSubjects_TV = findViewById(R.id.totalNumberOfSubjects_AM); 370 | 371 | // put data in layout 372 | updateUI(); 373 | } 374 | 375 | @Override 376 | public boolean onCreateOptionsMenu(Menu menu) 377 | { 378 | MenuInflater inflater = getMenuInflater(); 379 | inflater.inflate(R.menu.settings_menu, menu); 380 | return true; 381 | } 382 | 383 | public void updateUI() 384 | { 385 | numberOfSubjects_TV.setText(String.valueOf(numberOfSubjectsToTest)); 386 | totalNumberOfSubjects_TV.setText(String.format("Subjects (%d solved / %d)", solvedNumberOfSubjects, databaseHandler.getList().size())); 387 | countdown_TV.setText(Utils.calculateDaysLeft(examDate)); 388 | } 389 | 390 | // methods - alert dialog 391 | public void createAlertDialogNumberOfQuestions() 392 | { 393 | DialogNumberOfQuestions dialog = new DialogNumberOfQuestions(); 394 | dialog.show(getSupportFragmentManager(), "DialogNumberOfQuestions"); 395 | } 396 | 397 | public void onChangeExamDateMenuItemClicked() 398 | { 399 | MyDialogDatePicker dp = new MyDialogDatePicker(); 400 | dp.show(getSupportFragmentManager(), "MyDialogDatePicker"); 401 | } 402 | 403 | @Override 404 | public void getNumber(int number) 405 | { 406 | numberOfSubjectsToTest = number; 407 | 408 | // save the new value to SharedPreferences 409 | SharedPreferences sp = getSharedPreferences(SHARED_PREFS, MODE_PRIVATE); 410 | SharedPreferences.Editor editor = sp.edit(); 411 | editor.putInt(NUMBER_OF_SUBJECTS, numberOfSubjectsToTest); 412 | editor.apply(); 413 | 414 | // update UI 415 | numberOfSubjects_TV.setText(String.valueOf(numberOfSubjectsToTest)); 416 | } 417 | 418 | @Override 419 | public void onDateSet(DatePicker view, int year, int month, int dayOfMonth) 420 | { 421 | examDate = LocalDate.of(year, month + 1, dayOfMonth); 422 | 423 | // save new values to shared preferences 424 | SharedPreferences sp = getSharedPreferences(SHARED_PREFS, MODE_PRIVATE); 425 | SharedPreferences.Editor editor = sp.edit(); 426 | editor.putInt(EXAM_YEAR, year); 427 | editor.putInt(EXAM_MONTH, month + 1); 428 | editor.putInt(EXAM_DAY, dayOfMonth); 429 | editor.apply(); 430 | 431 | // update UI 432 | updateUI(); 433 | } 434 | } 435 | -------------------------------------------------------------------------------- /app/src/main/java/remcv/com/github/examprep/TestSubjectsActivity.java: -------------------------------------------------------------------------------- 1 | package remcv.com.github.examprep; 2 | 3 | import androidx.appcompat.app.AppCompatActivity; 4 | 5 | import android.content.Intent; 6 | import android.os.Bundle; 7 | import android.widget.ListView; 8 | import android.widget.TextView; 9 | 10 | import com.google.gson.Gson; 11 | import com.google.gson.reflect.TypeToken; 12 | 13 | import java.lang.reflect.Type; 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | 17 | import remcv.com.github.examprep.model.ExamItem; 18 | import remcv.com.github.examprep.utils.TableConstants; 19 | import remcv.com.github.examprep.utils.Utils; 20 | import remcv.com.github.examprep.view.ExamItemAdapter; 21 | 22 | public class TestSubjectsActivity extends AppCompatActivity implements TableConstants 23 | { 24 | // fields - layout 25 | private TextView minutes_TV; 26 | private ListView subjects_LV; 27 | 28 | // fields - data 29 | private List examItems; 30 | private ExamItemAdapter adapter; 31 | 32 | // methods - life cycle 33 | @Override 34 | protected void onCreate(Bundle savedInstanceState) 35 | { 36 | super.onCreate(savedInstanceState); 37 | setContentView(R.layout.activity_test_subjects); 38 | 39 | // initialize layout 40 | initializeLayout(); 41 | 42 | // initialize data 43 | initialDataSetup(); 44 | 45 | // update layout 46 | updateLayout(); 47 | } 48 | 49 | // methods - data 50 | public void initialDataSetup() 51 | { 52 | // get list of Exam items 53 | Intent getListIntent = getIntent(); 54 | String listStringJson = getListIntent.getStringExtra(TableConstants.RANDOM_LIST); 55 | 56 | Gson gson = new Gson(); 57 | Type type = new TypeToken>() {}.getType(); 58 | 59 | examItems = gson.fromJson(listStringJson, type); 60 | 61 | // set adapter 62 | adapter = new ExamItemAdapter(examItems, TestSubjectsActivity.this); 63 | } 64 | 65 | // methods - layout 66 | public void initializeLayout() 67 | { 68 | minutes_TV = findViewById(R.id.minutesTextView_ATS); 69 | subjects_LV = findViewById(R.id.problemsListView_ATS); 70 | } 71 | 72 | public void updateLayout() 73 | { 74 | // minutes 75 | String minutes = Utils.calculateMinutes(examItems.size()); 76 | minutes_TV.setText(minutes); 77 | 78 | // put items in listView 79 | subjects_LV.setAdapter(adapter); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /app/src/main/java/remcv/com/github/examprep/UpdateDeleteItemActivity.java: -------------------------------------------------------------------------------- 1 | package remcv.com.github.examprep; 2 | 3 | import androidx.appcompat.app.AppCompatActivity; 4 | 5 | import android.content.Intent; 6 | import android.os.Bundle; 7 | import android.widget.Button; 8 | import android.widget.CheckBox; 9 | 10 | import com.google.android.material.textfield.TextInputLayout; 11 | 12 | import remcv.com.github.examprep.utils.TableConstants; 13 | import remcv.com.github.examprep.utils.Utils; 14 | 15 | public class UpdateDeleteItemActivity extends AppCompatActivity implements TableConstants 16 | { 17 | // fields - data 18 | private int indexOfItemInList; 19 | 20 | // fields - layout 21 | private TextInputLayout categoryNumber_til; 22 | private TextInputLayout problem_til; 23 | private Button updateButton; 24 | private Button deleteButton; 25 | private CheckBox subjectIsSolved_CB; 26 | 27 | @Override 28 | protected void onCreate(Bundle savedInstanceState) 29 | { 30 | super.onCreate(savedInstanceState); 31 | setContentView(R.layout.activity_update_delete_item); 32 | 33 | // initialize layout 34 | initializeLayout(); 35 | 36 | // initialize data 37 | initializeData(); 38 | 39 | // handle events 40 | deleteButton.setOnClickListener(v -> onDeleteButtonClicked()); 41 | updateButton.setOnClickListener(v -> onUpdateButtonClicked()); 42 | } 43 | 44 | // methods - handle events 45 | public void onDeleteButtonClicked() 46 | { 47 | // create intent 48 | Intent intent = new Intent(UpdateDeleteItemActivity.this, MainActivity.class); 49 | intent.putExtra(TableConstants.INDEX, indexOfItemInList); 50 | intent.putExtra(TableConstants.BUTTON_NAME, "deleteButton"); 51 | 52 | // set the result code 53 | setResult(RESULT_OK, intent); 54 | 55 | // close activity 56 | finish(); 57 | } 58 | 59 | public void onUpdateButtonClicked() 60 | { 61 | // validate user input 62 | if (Utils.isNumberValid(categoryNumber_til) & Utils.isStringInputValid(problem_til)) 63 | { 64 | // gather data 65 | int categoryNumber = Integer.parseInt(categoryNumber_til.getEditText().getText().toString()); 66 | String problem = problem_til.getEditText().getText().toString(); 67 | boolean isDone = subjectIsSolved_CB.isChecked(); 68 | 69 | // make Intent and put the data in extras 70 | Intent intent = new Intent(UpdateDeleteItemActivity.this, MainActivity.class); 71 | intent.putExtra(TableConstants.CATEGORY_NUMBER, categoryNumber); 72 | intent.putExtra(TableConstants.PROBLEM, problem); 73 | intent.putExtra(TableConstants.IS_DONE, isDone); 74 | intent.putExtra(TableConstants.INDEX, indexOfItemInList); 75 | intent.putExtra(TableConstants.BUTTON_NAME, "updateButton"); 76 | 77 | // set result to pass to MainActivity 78 | setResult(RESULT_OK, intent); 79 | 80 | // finish current activity without starting a new MainActivity 81 | finish(); 82 | } 83 | } 84 | 85 | // methods - data 86 | public void initializeData() 87 | { 88 | Intent intent = getIntent(); 89 | 90 | int categoryNumber = intent.getIntExtra(TableConstants.CATEGORY_NUMBER, 0); 91 | String problem = intent.getStringExtra(TableConstants.PROBLEM); 92 | boolean isDone = intent.getBooleanExtra(TableConstants.IS_DONE, false); 93 | indexOfItemInList = intent.getIntExtra(TableConstants.INDEX, 0); 94 | 95 | categoryNumber_til.getEditText().setText(String.valueOf(categoryNumber)); 96 | problem_til.getEditText().setText(problem); 97 | subjectIsSolved_CB.setChecked(isDone); 98 | } 99 | 100 | // methods - layout 101 | public void initializeLayout() 102 | { 103 | categoryNumber_til = findViewById(R.id.categoryNumberTextInputLayout_AUDI); 104 | problem_til = findViewById(R.id.problemTextInputLayout_AUDI); 105 | updateButton = findViewById(R.id.updateItemButton_AUDI); 106 | deleteButton = findViewById(R.id.deleteItemButton_AUDI); 107 | subjectIsSolved_CB = findViewById(R.id.subjectSolvedCheckBox_AUDI); 108 | } 109 | } -------------------------------------------------------------------------------- /app/src/main/java/remcv/com/github/examprep/controller/DatabaseCrud.java: -------------------------------------------------------------------------------- 1 | package remcv.com.github.examprep.controller; 2 | 3 | import java.io.File; 4 | import java.util.List; 5 | 6 | public interface DatabaseCrud 7 | { 8 | public abstract boolean add(T item); 9 | public abstract T read(int id); 10 | public abstract boolean update(T item); 11 | public abstract boolean delete(int id); 12 | public abstract void loadDb(File databaseFile); 13 | public abstract void saveDb(File databaseFile); 14 | public abstract String getDatabasePath(); 15 | public abstract List getList(); 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/remcv/com/github/examprep/controller/DatabaseHandler.java: -------------------------------------------------------------------------------- 1 | package remcv.com.github.examprep.controller; 2 | 3 | import android.app.Activity; 4 | import android.util.Log; 5 | import android.widget.Toast; 6 | 7 | import androidx.appcompat.app.AppCompatActivity; 8 | 9 | import java.io.BufferedReader; 10 | import java.io.BufferedWriter; 11 | import java.io.File; 12 | import java.io.FileReader; 13 | import java.io.FileWriter; 14 | import java.io.IOException; 15 | import java.util.ArrayList; 16 | import java.util.List; 17 | 18 | import remcv.com.github.examprep.model.ExamItem; 19 | 20 | public class DatabaseHandler implements DatabaseCrud 21 | { 22 | // fields 23 | private static final String FILE_PATH = "database.csv"; 24 | private static final String TAG = "ExamPrep"; 25 | private List examItemsList; 26 | private Activity mActivity; 27 | 28 | // constructor 29 | public DatabaseHandler(Activity activity) 30 | { 31 | mActivity = activity; 32 | examItemsList = new ArrayList(); 33 | } 34 | 35 | // methods from interface 36 | @Override 37 | public boolean add(ExamItem item) 38 | { 39 | return examItemsList.add(item); 40 | } 41 | 42 | @Override 43 | public ExamItem read(int id) 44 | { 45 | // TODO 46 | return null; 47 | } 48 | 49 | @Override 50 | public boolean update(ExamItem item) 51 | { 52 | // TODO 53 | return false; 54 | } 55 | 56 | @Override 57 | public boolean delete(int id) 58 | { 59 | // TODO 60 | return false; 61 | } 62 | 63 | @Override 64 | public void loadDb(File databaseFile) 65 | { 66 | try (BufferedReader br = new BufferedReader(new FileReader(databaseFile))) 67 | { 68 | int categoryNumber; 69 | String problem; 70 | boolean isDone; 71 | 72 | String s; 73 | String[] oneRow; 74 | 75 | while((s = br.readLine()) != null) 76 | { 77 | oneRow = s.split(",", 3); 78 | categoryNumber = Integer.parseInt(oneRow[0]); 79 | problem = oneRow[1]; 80 | isDone = Boolean.parseBoolean(oneRow[2]); 81 | 82 | ExamItem item = new ExamItem(categoryNumber, problem, isDone); 83 | examItemsList.add(item); 84 | } 85 | } 86 | catch (IOException e) 87 | { 88 | Log.e(TAG, "loadDb() exception thrown " + e.toString()); 89 | Toast.makeText(mActivity.getApplicationContext(), "Load failed ...", Toast.LENGTH_SHORT).show(); 90 | } 91 | } 92 | 93 | @Override 94 | public void saveDb(File databaseFile) 95 | { 96 | try (BufferedWriter bw = new BufferedWriter(new FileWriter(databaseFile))) 97 | { 98 | StringBuilder oneItem = new StringBuilder(); 99 | 100 | for (ExamItem item : examItemsList) 101 | { 102 | oneItem.append(item.getCategoryNumber()); 103 | oneItem.append(","); 104 | oneItem.append(item.getProblem()); 105 | oneItem.append(","); 106 | oneItem.append(item.getIsDone()); 107 | 108 | bw.write(oneItem.toString()); 109 | Log.d(TAG, "saveDb() item " + item.toString()); 110 | bw.newLine(); 111 | bw.flush(); 112 | 113 | oneItem.delete(0, oneItem.length()); 114 | } 115 | } 116 | catch (IOException e) 117 | { 118 | Log.e(TAG, "saveDb() exception thrown " + e.toString()); 119 | } 120 | } 121 | 122 | // methods - getters 123 | @Override 124 | public List getList() 125 | { 126 | return examItemsList; 127 | } 128 | 129 | @Override 130 | public String getDatabasePath() 131 | { 132 | return FILE_PATH; 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /app/src/main/java/remcv/com/github/examprep/model/ExamItem.java: -------------------------------------------------------------------------------- 1 | package remcv.com.github.examprep.model; 2 | 3 | public class ExamItem implements Comparable 4 | { 5 | // fields 6 | private int categoryNumber; 7 | private String problem; 8 | private boolean isDone; 9 | 10 | // constructor 11 | public ExamItem(int categoryNumber, String problem, boolean isDone) 12 | { 13 | this.categoryNumber = categoryNumber; 14 | this.problem = problem; 15 | this.isDone = isDone; 16 | } 17 | 18 | // methods - getters 19 | public int getCategoryNumber() 20 | { 21 | return categoryNumber; 22 | } 23 | 24 | public String getProblem() 25 | { 26 | return problem; 27 | } 28 | 29 | public boolean getIsDone() 30 | { 31 | return isDone; 32 | } 33 | 34 | // methods - interface 35 | @Override 36 | public int compareTo(ExamItem other) 37 | { 38 | // by category number, than alphabetical 39 | if (this.categoryNumber == other.getCategoryNumber()) 40 | { 41 | return this.problem.compareTo(other.getProblem()); 42 | } 43 | else 44 | { 45 | return this.categoryNumber - other.getCategoryNumber(); 46 | } 47 | } 48 | 49 | // methods - toString 50 | @Override 51 | public String toString() 52 | { 53 | return "ExamItem{" + 54 | "categoryNumber=" + categoryNumber + 55 | ", problem='" + problem + '\'' + 56 | ", isDone=" + isDone + 57 | '}'; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /app/src/main/java/remcv/com/github/examprep/utils/TableConstants.java: -------------------------------------------------------------------------------- 1 | package remcv.com.github.examprep.utils; 2 | 3 | public interface TableConstants 4 | { 5 | public static final String CATEGORY_NUMBER = "categoryNumber"; 6 | public static final String PROBLEM = "problem"; 7 | public static final String INDEX = "index"; 8 | public static final String BUTTON_NAME = "buttonName"; 9 | public static final String IS_DONE = "isDone"; 10 | public static final String RANDOM_LIST = "randomList"; 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/remcv/com/github/examprep/utils/Utils.java: -------------------------------------------------------------------------------- 1 | package remcv.com.github.examprep.utils; 2 | 3 | import android.util.Log; 4 | 5 | import com.google.android.material.textfield.TextInputLayout; 6 | 7 | import java.time.LocalDate; 8 | import java.time.Period; 9 | import java.time.chrono.ChronoPeriod; 10 | import java.time.temporal.ChronoUnit; 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | import java.util.Random; 14 | 15 | import remcv.com.github.examprep.model.ExamItem; 16 | 17 | public class Utils 18 | { 19 | // fields 20 | public static final int MINUTES_PER_SUBJECT = 18; 21 | 22 | // methods 23 | public static String calculateDaysLeft(LocalDate examDate) 24 | { 25 | long daysLeft = ChronoUnit.DAYS.between(LocalDate.now(), examDate); 26 | return String.valueOf(daysLeft); 27 | } 28 | 29 | public static String calculateMinutes(int numberOfSubjects) 30 | { 31 | return String.valueOf(numberOfSubjects * MINUTES_PER_SUBJECT); 32 | } 33 | 34 | public static List generateRandomSubjectList(int numberOfSubjects, List list) 35 | { 36 | // setup 37 | int listSize = list.size(); 38 | long numberOfCateg = list.stream() 39 | .map(examItem -> Integer.valueOf(examItem.getCategoryNumber())) 40 | .distinct() 41 | .count(); 42 | 43 | ArrayList indexesOfTakenSubjects = new ArrayList<>(); 44 | ArrayList categoriesPicked = new ArrayList<>(); 45 | 46 | // check if numberOfSubjects is greater than the subjects from the list 47 | if (numberOfSubjects > listSize) 48 | { 49 | return null; 50 | } 51 | else if (numberOfSubjects > (int) numberOfCateg) 52 | { 53 | return null; 54 | } 55 | else 56 | { 57 | Random random = new Random(); 58 | int tempNumber; 59 | 60 | while (indexesOfTakenSubjects.size() < numberOfSubjects) 61 | { 62 | tempNumber = random.nextInt(listSize); 63 | 64 | if (indexesOfTakenSubjects.contains(tempNumber)) 65 | { 66 | continue; 67 | } 68 | else 69 | { 70 | if (categoriesPicked.contains(list.get(tempNumber).getCategoryNumber())) 71 | { 72 | continue; 73 | } 74 | else 75 | { 76 | indexesOfTakenSubjects.add(tempNumber); 77 | categoriesPicked.add(list.get(tempNumber).getCategoryNumber()); 78 | } 79 | } 80 | } 81 | } 82 | 83 | ArrayList listToReturn = new ArrayList<>(); 84 | 85 | for (Integer i : indexesOfTakenSubjects) 86 | { 87 | listToReturn.add(list.get(i)); 88 | } 89 | 90 | return listToReturn; 91 | } 92 | 93 | // input validation methods 94 | public static boolean isNumberValid(TextInputLayout til) 95 | { 96 | String idString = til.getEditText().getText().toString(); 97 | 98 | // check if field is empty 99 | if (idString.trim().isEmpty()) 100 | { 101 | til.setError("Empty fields are not allowed"); 102 | return false; 103 | } 104 | else 105 | { 106 | try 107 | { 108 | Integer.parseInt(idString); 109 | til.setError(null); 110 | return true; 111 | } 112 | catch (NumberFormatException e) 113 | { 114 | til.setError("Invalid number"); 115 | return false; 116 | } 117 | } 118 | } 119 | 120 | public static boolean isStringInputValid(TextInputLayout til) 121 | { 122 | String problem = til.getEditText().getText().toString(); 123 | 124 | if (problem.trim().isEmpty()) 125 | { 126 | til.setError("Empty fields are not allowed"); 127 | return false; 128 | } 129 | else 130 | { 131 | til.setError(null); 132 | return true; 133 | } 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /app/src/main/java/remcv/com/github/examprep/view/DialogNumberOfQuestions.java: -------------------------------------------------------------------------------- 1 | package remcv.com.github.examprep.view; 2 | 3 | import android.app.AlertDialog; 4 | import android.app.Dialog; 5 | import android.content.Context; 6 | import android.content.DialogInterface; 7 | import android.os.Bundle; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.widget.EditText; 11 | 12 | import androidx.annotation.NonNull; 13 | import androidx.annotation.Nullable; 14 | import androidx.appcompat.app.AppCompatDialogFragment; 15 | 16 | import remcv.com.github.examprep.R; 17 | 18 | public class DialogNumberOfQuestions extends AppCompatDialogFragment 19 | { 20 | // fields 21 | private DialogNumberOfQuestionsListener dnoq; 22 | 23 | // nested interface 24 | public interface DialogNumberOfQuestionsListener 25 | { 26 | void getNumber(int number); 27 | } 28 | 29 | // constructor 30 | @NonNull 31 | @Override 32 | public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) 33 | { 34 | // 35 | 36 | 37 | // 38 | AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); 39 | 40 | LayoutInflater inflater = getActivity().getLayoutInflater(); 41 | View view = inflater.inflate(R.layout.dialog_number_of_questions, null); 42 | EditText numberOfQuestions_ET = view.findViewById(R.id.numberOfQuestions_ET_DNQ); 43 | 44 | builder.setView(view) 45 | .setTitle("Number of questions for test") 46 | .setNegativeButton("cancel", new DialogInterface.OnClickListener() 47 | { 48 | @Override 49 | public void onClick(DialogInterface dialog, int which) 50 | { 51 | dismiss(); 52 | } 53 | }) 54 | .setPositiveButton("save", new DialogInterface.OnClickListener() 55 | { 56 | @Override 57 | public void onClick(DialogInterface dialog, int which) 58 | { 59 | int numberOfQuestions = Integer.parseInt(numberOfQuestions_ET.getText().toString()); 60 | dnoq.getNumber(numberOfQuestions); 61 | } 62 | }); 63 | 64 | 65 | 66 | return builder.create(); 67 | } 68 | 69 | // methods 70 | @Override 71 | public void onAttach(@NonNull Context context) 72 | { 73 | super.onAttach(context); 74 | 75 | try 76 | { 77 | dnoq = (DialogNumberOfQuestionsListener) context; 78 | } 79 | catch (ClassCastException e) 80 | { 81 | throw new ClassCastException(context.toString() + " must implement DialogNumberOfQuestionsListener"); 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /app/src/main/java/remcv/com/github/examprep/view/ExamItemAdapter.java: -------------------------------------------------------------------------------- 1 | package remcv.com.github.examprep.view; 2 | 3 | import android.app.Activity; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.BaseAdapter; 8 | import android.widget.ImageView; 9 | import android.widget.TextView; 10 | 11 | import java.util.List; 12 | 13 | import remcv.com.github.examprep.R; 14 | import remcv.com.github.examprep.model.ExamItem; 15 | 16 | public class ExamItemAdapter extends BaseAdapter 17 | { 18 | // fields 19 | private List list; 20 | private Activity activity; 21 | 22 | // constructor 23 | public ExamItemAdapter(List list, Activity activity) 24 | { 25 | this.list = list; 26 | this.activity = activity; 27 | } 28 | 29 | // methods from parent class 30 | @Override 31 | public int getCount() 32 | { 33 | return list.size(); 34 | } 35 | 36 | @Override 37 | public ExamItem getItem(int position) 38 | { 39 | return list.get(position); 40 | } 41 | 42 | @Override 43 | public long getItemId(int position) 44 | { 45 | return 0; 46 | } 47 | 48 | @Override 49 | public View getView(int position, View convertView, ViewGroup parent) 50 | { 51 | View oneExamItemView; 52 | LayoutInflater inflater = LayoutInflater.from(activity); 53 | oneExamItemView = inflater.inflate(R.layout.exam_item, parent, false); 54 | 55 | // initialize layout 56 | TextView categoryNumber_TV = oneExamItemView.findViewById(R.id.categoryNumberTextView_EI); 57 | TextView problem_TV = oneExamItemView.findViewById(R.id.problemTextView_EI); 58 | 59 | // put data in view 60 | ExamItem examItem = list.get(position); 61 | categoryNumber_TV.setText(String.valueOf(examItem.getCategoryNumber())); 62 | problem_TV.setText(examItem.getProblem()); 63 | 64 | if (examItem.getIsDone()) 65 | { 66 | categoryNumber_TV.setBackgroundResource(R.drawable.circle_subject_solved); 67 | } 68 | 69 | return oneExamItemView; 70 | } 71 | 72 | // methods - setters 73 | public void setList(List list) 74 | { 75 | this.list = list; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /app/src/main/java/remcv/com/github/examprep/view/MyDialogDatePicker.java: -------------------------------------------------------------------------------- 1 | package remcv.com.github.examprep.view; 2 | 3 | import android.app.DatePickerDialog; 4 | import android.app.Dialog; 5 | import android.os.Bundle; 6 | 7 | import androidx.annotation.NonNull; 8 | import androidx.annotation.Nullable; 9 | import androidx.fragment.app.DialogFragment; 10 | 11 | import java.util.Calendar; 12 | 13 | public class MyDialogDatePicker extends DialogFragment 14 | { 15 | @NonNull 16 | @Override 17 | public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) 18 | { 19 | // use the current date as the default date in the picker 20 | final Calendar c = Calendar.getInstance(); 21 | int year = c.get(Calendar.YEAR); 22 | int month = c.get(Calendar.MONTH); 23 | int day = c.get(Calendar.DAY_OF_MONTH); 24 | 25 | // create an instance of DatePickerDialog and return it 26 | return new DatePickerDialog(getActivity(), (DatePickerDialog.OnDateSetListener) getActivity(), year, month, day); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/check_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remcv/ExamPrep-Android/da0fbe255c73bb2d2a1a5605c2152b8ddbd4a0f5/app/src/main/res/drawable/check_icon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/circle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/circle2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/circle_subject_solved.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/classroom.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remcv/ExamPrep-Android/da0fbe255c73bb2d2a1a5605c2152b8ddbd4a0f5/app/src/main/res/drawable/classroom.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_add_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_notes_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 10 | 12 | 14 | 16 | 18 | 20 | 22 | 24 | 26 | 28 | 30 | 32 | 34 | 36 | 38 | 40 | 42 | 44 | 46 | 48 | 50 | 52 | 54 | 56 | 58 | 60 | 62 | 64 | 66 | 68 | 70 | 72 | 74 | 75 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/mountains.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remcv/ExamPrep-Android/da0fbe255c73bb2d2a1a5605c2152b8ddbd4a0f5/app/src/main/res/drawable/mountains.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/pencil.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remcv/ExamPrep-Android/da0fbe255c73bb2d2a1a5605c2152b8ddbd4a0f5/app/src/main/res/drawable/pencil.jpg -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_add_exam_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 18 | 19 | 28 | 29 | 36 | 37 | 42 | 43 | 44 | 51 | 52 | 57 | 58 | 59 |