├── .gitignore
├── .idea
├── .gitignore
├── .name
├── compiler.xml
├── deploymentTargetSelector.xml
├── gradle.xml
├── material_theme_project_new.xml
├── migrations.xml
├── misc.xml
├── other.xml
└── vcs.xml
├── README.md
├── app
├── .gitignore
├── build.gradle.kts
├── google-services.json
├── proguard-rules.pro
├── release
│ └── app-release.aab
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── example
│ │ └── to_do_app
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── example
│ │ │ └── to_do_app
│ │ │ ├── AddTaskFragment.java
│ │ │ ├── EditTaskActivity.java
│ │ │ ├── MainActivity.java
│ │ │ ├── MenuActivity.java
│ │ │ ├── RegistrationActivity.java
│ │ │ ├── Task.java
│ │ │ └── ViewTasksFragment.java
│ └── res
│ │ ├── drawable-nodpi
│ │ └── ocean_blue_copy_space_abstract_paper_waves.jpg
│ │ ├── drawable
│ │ ├── baseline_delete_24.xml
│ │ ├── baseline_edit_24.xml
│ │ ├── ic_launcher_background.xml
│ │ ├── ic_launcher_foreground.xml
│ │ └── icons8_wave_96.png
│ │ ├── font
│ │ ├── oxygen.xml
│ │ ├── oxygen_bold.xml
│ │ └── oxygen_light.ttf
│ │ ├── layout
│ │ ├── activity_edit_task.xml
│ │ ├── activity_main.xml
│ │ ├── activity_menu.xml
│ │ ├── fragment_add_task.xml
│ │ ├── fragment_view_tasks.xml
│ │ ├── item_task_card.xml
│ │ └── register_popup.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── values-night
│ │ ├── colors.xml
│ │ ├── styles.xml
│ │ └── themes.xml
│ │ ├── values
│ │ ├── colors.xml
│ │ ├── font_certs.xml
│ │ ├── preloaded_fonts.xml
│ │ ├── strings.xml
│ │ ├── styles.xml
│ │ └── themes.xml
│ │ └── xml
│ │ ├── backup_rules.xml
│ │ └── data_extraction_rules.xml
│ └── test
│ └── java
│ └── com
│ └── example
│ └── to_do_app
│ ├── AddTaskFragmentTest.java
│ └── ViewTasksFragmentTest.java
├── build.gradle.kts
├── gradle.properties
├── gradle
├── libs.versions.toml
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle.kts
└── v0.2.0_Screenshot_Pixel8Pro
├── AddTask.jpg
├── AddTaskWImportance-Dark.jpg
├── Firestore.jpg
├── Importance.jpg
├── UpdateTask.jpg
├── ViewTasks.jpg
├── ViewTasksWImportance-Dark.jpg
├── v0.2.0_Add_task_frag.png
├── v0.2.0_Firestore_db.jpg
├── v0.2.0_Main_login_screen.png
├── v0.2.0_Menu_add_view_logout.png
└── v0.2.0_Update_task.jpg
/.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 | local.properties
16 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/.idea/.name:
--------------------------------------------------------------------------------
1 | To-do-app
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/deploymentTargetSelector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
18 |
19 |
--------------------------------------------------------------------------------
/.idea/material_theme_project_new.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/migrations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/.idea/other.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## v0.5.0
2 | - A dark mode to improve user experience.
3 |
4 | - Further implementation of the CRUD Operations - Added task due date and importance level, both are full CRUD similar to Title and description.
5 |
6 | - Adjusted UI, theme and colours, font size for a better aesthetic.
7 |
8 |
9 | ## v0.4.1
10 | - Added a separate view for registration, require user to confirm password upon creating an account.
11 |
12 | ## v0.4.0
13 |
14 | - CRUD Operations are now fully functional.
15 |
16 | - Firebase Integration: Authentication and database.
17 |
18 | - Enhanced UI/UX.
19 |
20 | - Task Management: Tasks can now be viewed, added, edited, and deleted directly within the app..
21 |
22 |
23 | 
24 |
25 | 
26 |
27 | 
28 |
29 | 
30 |
31 | ## Documentation
32 | For further guidance and detailed documentation, please refer to the following resources:
33 |
34 | - Android Developers Documentation: Android Docs --> https://developer.android.com/guide/
35 | - Firebase Documentation: Firebase Docs --> https://firebase.google.com/docs/
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/app/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id("com.android.application")
3 | // Add the Google services Gradle plugin
4 | id("com.google.gms.google-services")
5 | }
6 |
7 | android {
8 | namespace = "com.example.to_do_app"
9 | compileSdk = 34
10 |
11 | defaultConfig {
12 | applicationId = "com.example.to_do_app"
13 | minSdk = 24
14 | targetSdk = 34
15 | versionCode = 1
16 | versionName = "1.0"
17 |
18 | testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
19 | }
20 |
21 | buildTypes {
22 | release {
23 | isMinifyEnabled = false
24 | proguardFiles(
25 | getDefaultProguardFile("proguard-android-optimize.txt"),
26 | "proguard-rules.pro"
27 | )
28 | }
29 | }
30 | compileOptions {
31 | sourceCompatibility = JavaVersion.VERSION_1_8
32 | targetCompatibility = JavaVersion.VERSION_1_8
33 | }
34 | }
35 |
36 | dependencies {
37 |
38 | implementation(libs.appcompat)
39 | implementation(libs.material)
40 | implementation(libs.activity)
41 | implementation(libs.constraintlayout)
42 | testImplementation(libs.junit)
43 | androidTestImplementation(libs.ext.junit)
44 | androidTestImplementation(libs.espresso.core)
45 |
46 | // Import the Firebase BoM
47 | implementation(platform("com.google.firebase:firebase-bom:33.1.2"))
48 | implementation("com.google.firebase:firebase-analytics")
49 |
50 | // Add dependencies for Firebase authentication and Firestore
51 | implementation ("com.google.firebase:firebase-auth")
52 | implementation ("com.google.firebase:firebase-firestore")
53 | }
54 |
--------------------------------------------------------------------------------
/app/google-services.json:
--------------------------------------------------------------------------------
1 | {
2 | "project_info": {
3 | "project_number": "984170943112",
4 | "project_id": "todoapp-f2ae7",
5 | "storage_bucket": "todoapp-f2ae7.appspot.com"
6 | },
7 | "client": [
8 | {
9 | "client_info": {
10 | "mobilesdk_app_id": "1:984170943112:android:ee305ffda871015c28453d",
11 | "android_client_info": {
12 | "package_name": "com.example.to_do_app"
13 | }
14 | },
15 | "oauth_client": [],
16 | "api_key": [
17 | {
18 | "current_key": "AIzaSyAgjGnyahVSIdV4jKIYZxHTrG4AedG1Ee4"
19 | }
20 | ],
21 | "services": {
22 | "appinvite_service": {
23 | "other_platform_oauth_client": []
24 | }
25 | }
26 | }
27 | ],
28 | "configuration_version": "1"
29 | }
--------------------------------------------------------------------------------
/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/release/app-release.aab:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hieudku/TasksManagementApp--Android-Java-Firebase/84e91b106e4ddbd20f3068fefaac3dfe6117983a/app/release/app-release.aab
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/example/to_do_app/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.example.to_do_app;
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 | @Test
21 | public void useAppContext() {
22 | // Context of the app under test.
23 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
24 | assertEquals("com.example.to_do_app", appContext.getPackageName());
25 | }
26 | }
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
15 |
18 |
21 |
24 |
27 |
30 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/to_do_app/AddTaskFragment.java:
--------------------------------------------------------------------------------
1 | package com.example.to_do_app;
2 |
3 | import android.os.Bundle;
4 | import androidx.fragment.app.Fragment;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 | import android.widget.Button;
9 | import android.widget.EditText;
10 | import android.widget.Spinner;
11 | import android.widget.Toast;
12 | import androidx.annotation.NonNull;
13 | import androidx.annotation.Nullable;
14 | import com.google.firebase.Timestamp;
15 | import com.google.firebase.auth.FirebaseAuth;
16 | import com.google.firebase.auth.FirebaseUser;
17 | import com.google.firebase.firestore.FirebaseFirestore;
18 | import java.util.HashMap;
19 | import java.util.Map;
20 | import android.widget.DatePicker;
21 |
22 | public class AddTaskFragment extends Fragment {
23 | // Fields
24 | private EditText editTextTitle;
25 | private EditText editTextDescription;
26 | private DatePicker datePickerDueDate; // New DatePicker field
27 | private Spinner spinnerImportance; // Spinner for importance level
28 | private Button buttonSaveTask;
29 | private FirebaseFirestore db;
30 | private FirebaseUser user;
31 |
32 | @Nullable
33 | @Override
34 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
35 | @Nullable Bundle savedInstanceState) {
36 | // Inflate the layout for this fragment
37 | View view = inflater.inflate(R.layout.fragment_add_task, container, false);
38 |
39 | // Initialize user
40 | user = FirebaseAuth.getInstance().getCurrentUser();
41 | if (user == null) {
42 | Toast.makeText(getActivity(), "User not authenticated", Toast.LENGTH_SHORT).show();
43 | return view;
44 | }
45 |
46 | // Initialize UI components
47 | db = FirebaseFirestore.getInstance();
48 | editTextTitle = view.findViewById(R.id.edit_task_name);
49 | editTextDescription = view.findViewById(R.id.edit_task_description);
50 | datePickerDueDate = view.findViewById(R.id.datepicker_due_date); // Initialize DatePicker
51 | spinnerImportance = view.findViewById(R.id.spinner_importance); // Initialize Importance Spinner
52 | buttonSaveTask = view.findViewById(R.id.button_save_task);
53 |
54 | // Set up the click listener for the Save button
55 | buttonSaveTask.setOnClickListener(v -> saveTask());
56 |
57 | return view;
58 | }
59 |
60 | private void saveTask() {
61 | String title = editTextTitle.getText().toString().trim();
62 | String description = editTextDescription.getText().toString().trim();
63 |
64 | if (title.isEmpty()) {
65 | editTextTitle.setError("Title cannot be empty");
66 | editTextTitle.requestFocus();
67 | return;
68 | }
69 |
70 | // Get the selected date from DatePicker
71 | int day = datePickerDueDate.getDayOfMonth();
72 | int month = datePickerDueDate.getMonth();
73 | int year = datePickerDueDate.getYear();
74 | Timestamp dueDate = new Timestamp(new java.util.Date(year - 1900, month, day));
75 |
76 | // Get the selected importance level from the Spinner
77 | int importance = spinnerImportance.getSelectedItemPosition(); // Low = 0, Medium = 1, High = 2
78 |
79 | // Create task map with due date and importance
80 | String taskId = db.collection("tasks").document().getId();
81 | Map task = new HashMap<>();
82 | task.put("id", taskId);
83 | task.put("title", title);
84 | task.put("description", description);
85 | task.put("dueDate", dueDate);
86 | task.put("importance", importance); // Save importance level
87 | task.put("timestamp", Timestamp.now());
88 |
89 | db.collection("users").document(user.getUid()).collection("tasks").document(taskId)
90 | .set(task)
91 | .addOnSuccessListener(aVoid -> {
92 | Toast.makeText(getActivity(), "Task added", Toast.LENGTH_SHORT).show();
93 | editTextTitle.setText("");
94 | editTextDescription.setText("");
95 | })
96 | .addOnFailureListener(e -> {
97 | Toast.makeText(getActivity(), "Error adding task", Toast.LENGTH_SHORT).show();
98 | });
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/to_do_app/EditTaskActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.to_do_app;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.widget.DatePicker;
6 | import android.widget.EditText;
7 | import android.widget.Button;
8 | import android.widget.Spinner;
9 | import android.widget.ArrayAdapter;
10 | import android.widget.Toast;
11 | import androidx.appcompat.app.AppCompatActivity;
12 | import com.google.firebase.auth.FirebaseAuth;
13 | import com.google.firebase.auth.FirebaseUser;
14 | import com.google.firebase.firestore.FirebaseFirestore;
15 | import com.google.firebase.Timestamp;
16 |
17 | import java.util.Calendar;
18 | import java.util.Date;
19 | import java.util.HashMap;
20 | import java.util.Map;
21 |
22 | public class EditTaskActivity extends AppCompatActivity {
23 | private EditText editTextTitle;
24 | private EditText editTextDescription;
25 | private DatePicker datePickerDueDate;
26 | private Spinner spinnerImportance; // New spinner for importance level
27 | private Button buttonUpdateTask;
28 | private FirebaseFirestore db;
29 | private FirebaseUser user;
30 | private String taskId;
31 | private Timestamp dueDate;
32 | private Integer importance;
33 |
34 | @Override
35 | protected void onCreate(Bundle savedInstanceState) {
36 | super.onCreate(savedInstanceState);
37 | setContentView(R.layout.activity_edit_task);
38 |
39 | // Find title, description, due date picker, importance spinner, and update button
40 | editTextTitle = findViewById(R.id.edit_task_name);
41 | editTextDescription = findViewById(R.id.edit_task_description);
42 | datePickerDueDate = findViewById(R.id.datepicker_due_date);
43 | spinnerImportance = findViewById(R.id.spinnerImportance); // Initialize Spinner for importance
44 | buttonUpdateTask = findViewById(R.id.button_update_task);
45 |
46 | // Initialize Firebase database and user
47 | db = FirebaseFirestore.getInstance();
48 | user = FirebaseAuth.getInstance().getCurrentUser();
49 |
50 | // Setup spinner with importance levels
51 | ArrayAdapter adapter = ArrayAdapter.createFromResource(this,
52 | R.array.importance_levels, android.R.layout.simple_spinner_item);
53 | adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
54 | spinnerImportance.setAdapter(adapter);
55 |
56 | // Get task details from intent
57 | Intent intent = getIntent();
58 | if (intent != null) {
59 | taskId = intent.getStringExtra("taskId");
60 | editTextTitle.setText(intent.getStringExtra("taskTitle"));
61 | editTextDescription.setText(intent.getStringExtra("taskDescription"));
62 |
63 | // Retrieve and set importance level
64 | importance = intent.getIntExtra("taskImportance", 0); // Default to 0 (Low)
65 | spinnerImportance.setSelection(importance);
66 |
67 | // Retrieve due date as long and convert it back to Timestamp
68 | long dueDateMillis = intent.getLongExtra("taskDueDate", -1);
69 | if (dueDateMillis != -1) {
70 | dueDate = new Timestamp(new Date(dueDateMillis));
71 |
72 | // Set the due date in the DatePicker
73 | Calendar calendar = Calendar.getInstance();
74 | calendar.setTime(dueDate.toDate());
75 | datePickerDueDate.updateDate(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH));
76 | }
77 | }
78 |
79 | // Set event for update button to call updateTask method
80 | buttonUpdateTask.setOnClickListener(v -> updateTask());
81 | }
82 |
83 | private void updateTask() {
84 | String title = editTextTitle.getText().toString().trim();
85 | String description = editTextDescription.getText().toString().trim();
86 |
87 | if (title.isEmpty()) {
88 | editTextTitle.setError("Title cannot be empty");
89 | editTextTitle.requestFocus();
90 | return;
91 | }
92 |
93 | if (user == null) {
94 | Toast.makeText(this, "User not authenticated", Toast.LENGTH_SHORT).show();
95 | return;
96 | }
97 |
98 | // Get the selected date from DatePicker
99 | int day = datePickerDueDate.getDayOfMonth();
100 | int month = datePickerDueDate.getMonth();
101 | int year = datePickerDueDate.getYear();
102 | dueDate = new Timestamp(new Date(year - 1900, month, day));
103 |
104 | // Get the selected importance level from Spinner
105 | importance = spinnerImportance.getSelectedItemPosition();
106 |
107 | // Create task map with updated data
108 | Map task = new HashMap<>();
109 | task.put("title", title);
110 | task.put("description", description);
111 | task.put("dueDate", dueDate);
112 | task.put("importance", importance); // Update importance level
113 |
114 | // Update task in Firestore
115 | db.collection("users").document(user.getUid()).collection("tasks").document(taskId)
116 | .update(task)
117 | .addOnSuccessListener(aVoid -> {
118 | Toast.makeText(EditTaskActivity.this, "Task updated", Toast.LENGTH_SHORT).show();
119 | finish();
120 | })
121 | .addOnFailureListener(e -> {
122 | Toast.makeText(EditTaskActivity.this, "Error updating task", Toast.LENGTH_SHORT).show();
123 | });
124 | }
125 |
126 | public Map createUpdatedTaskMap(String title, String description, Timestamp dueDate) {
127 | Map task = new HashMap<>();
128 | task.put("title", title);
129 | task.put("description", description);
130 | task.put("dueDate", dueDate);
131 | task.put("importance", importance); // Ensure importance is included
132 | task.put("timestamp", new Timestamp(new Date())); // Current time
133 | return task;
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/to_do_app/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.to_do_app;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.util.Log;
6 | import android.view.View;
7 | import android.widget.Button;
8 | import android.widget.EditText;
9 | import android.widget.Toast;
10 |
11 | import androidx.activity.EdgeToEdge;
12 | import androidx.appcompat.app.AppCompatActivity;
13 | import androidx.core.graphics.Insets;
14 | import androidx.core.view.ViewCompat;
15 | import androidx.core.view.WindowInsetsCompat;
16 |
17 | import com.google.firebase.FirebaseApp;
18 | import com.google.firebase.firestore.FirebaseFirestore;
19 | import com.google.firebase.firestore.QueryDocumentSnapshot;
20 | import com.google.firebase.firestore.QuerySnapshot;
21 | import com.google.firebase.auth.FirebaseAuth;
22 | import com.google.firebase.auth.FirebaseUser;
23 |
24 | import java.util.Objects;
25 |
26 | public class MainActivity extends AppCompatActivity {
27 | // Declare fields
28 | private EditText editTextEmail;
29 | private EditText editTextPassword;
30 | private Button buttonLogin;
31 | private Button buttonRegister;
32 | private FirebaseAuth mAuth;
33 | private FirebaseUser user;
34 | @Override
35 | protected void onCreate(Bundle savedInstanceState) {
36 |
37 | super.onCreate(savedInstanceState);
38 | EdgeToEdge.enable(this);
39 | setContentView(R.layout.activity_main);
40 |
41 | // Start Firebase
42 | FirebaseApp.initializeApp(this);
43 |
44 | // Test Firebase integration
45 | FirebaseFirestore db = FirebaseFirestore.getInstance();
46 | db.collection("sampleCollection")
47 | .get()
48 | .addOnCompleteListener(task -> {
49 | if (task.isSuccessful()) {
50 | for (QueryDocumentSnapshot document : task.getResult()) {
51 | Log.d("Firestore", document.getId() + " => " + document.getData());
52 | }
53 | } else {
54 | Log.w("Firestore", "Error getting documents.", task.getException());
55 | }
56 | });
57 |
58 | // Test user auth
59 | user = FirebaseAuth.getInstance().getCurrentUser();
60 | if (user != null) {
61 | Log.d("AddTaskFragment", "User is authenticated with UID" + user.getUid());
62 | } else {
63 | Log.d("AddTaskFragment", "User not authenticated");
64 | }
65 |
66 | // Initialize Firebase auth
67 | mAuth = FirebaseAuth.getInstance();
68 |
69 | editTextEmail = findViewById(R.id.email);
70 | editTextPassword = findViewById(R.id.password);
71 | buttonLogin = findViewById(R.id.login_button);
72 | buttonRegister = findViewById(R.id.register_button);
73 |
74 | // Gather button UI element by id
75 | Button buttonLogin = findViewById(R.id.login_button);
76 |
77 | // LOG IN LOGIC -- when login button is clicked
78 | buttonLogin.setOnClickListener(new View.OnClickListener() {
79 | @Override
80 | public void onClick(View view) {
81 |
82 | // Get username and password entered by the user
83 | String email = editTextEmail.getText().toString().trim();
84 | String password = editTextPassword.getText().toString().trim();
85 |
86 | // Prompt when either email or passwrod is empty
87 | if (email.isEmpty()) {
88 | editTextEmail.setError("Email is required to log in");
89 | editTextEmail.requestFocus();
90 | return;
91 | }
92 |
93 | if (password.isEmpty()) {
94 | editTextPassword.setError("Password is required to log in");
95 | editTextPassword.requestFocus();
96 | return;
97 | }
98 |
99 |
100 | // Call method with email and password entered as parameters to authenticate user's log in
101 | loginUser(email, password);
102 | }
103 | });
104 |
105 |
106 | // REGISTER LOGIC -- when click register button
107 | buttonRegister.setOnClickListener(new View.OnClickListener() {
108 | @Override
109 | public void onClick(View view) {
110 | Intent signUp = new Intent(MainActivity.this, RegistrationActivity.class );
111 | startActivity(signUp);
112 | finish();
113 | }
114 | });
115 |
116 | ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
117 | Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
118 | v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
119 | return insets;
120 | });
121 | }
122 |
123 | // LOG IN AUTH-- email and password as parameters to authenticate
124 | private void loginUser(String email, String password) {
125 | mAuth.signInWithEmailAndPassword(email, password).addOnCompleteListener(this, task -> {
126 | if (task.isSuccessful()) { // If login is successful
127 | FirebaseUser user = mAuth.getCurrentUser();
128 | // Then let user know
129 | Toast.makeText(MainActivity.this, "Login successful", Toast.LENGTH_SHORT).show();
130 |
131 | // Then take user to Menu/Dashboard activity
132 | Intent intent = new Intent(MainActivity.this, MenuActivity.class);
133 | startActivity(intent);
134 | finish();
135 | }
136 | else { // Sign in unsuccessful, then exception
137 | Toast.makeText(MainActivity.this, "Login failed" + Objects.requireNonNull(task.getException()).getMessage(), Toast.LENGTH_SHORT).show();
138 | }
139 | });
140 | }
141 |
142 | // Skip thje sign in screen if user already signed in
143 | @Override
144 | protected void onStart() {
145 | super.onStart();
146 | FirebaseUser currentUser = mAuth.getCurrentUser();
147 | if (currentUser != null) {
148 | Intent intent = new Intent(MainActivity.this, MenuActivity.class);
149 | startActivity(intent);
150 | finish();
151 | }
152 | }
153 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/to_do_app/MenuActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.to_do_app;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.widget.Button;
6 | import android.widget.Switch;
7 |
8 | import androidx.activity.EdgeToEdge;
9 | import androidx.appcompat.app.AppCompatActivity;
10 | import androidx.appcompat.app.AppCompatDelegate;
11 | import androidx.core.graphics.Insets;
12 | import androidx.core.view.ViewCompat;
13 | import androidx.core.view.WindowInsetsCompat;
14 | import androidx.fragment.app.Fragment;
15 | import androidx.fragment.app.FragmentManager;
16 | import androidx.fragment.app.FragmentTransaction;
17 |
18 | import com.google.firebase.auth.FirebaseAuth;
19 | import android.content.SharedPreferences;
20 |
21 | public class MenuActivity extends AppCompatActivity {
22 | // Declare fields
23 | private Button buttonLogout;
24 | private FirebaseAuth mAuth;
25 | private Switch darkModeSwitch;
26 | private SharedPreferences sharedPreferences;
27 | private SharedPreferences.Editor editor;
28 |
29 | @Override
30 | protected void onCreate(Bundle savedInstanceState) {
31 | super.onCreate(savedInstanceState);
32 | EdgeToEdge.enable(this);
33 | setContentView(R.layout.activity_menu);
34 |
35 | // Initialize UI elements
36 | Button addTaskButton = findViewById(R.id.add_task_button);
37 | Button viewTaskButton = findViewById(R.id.view_task_button);
38 | buttonLogout = findViewById(R.id.logout_button);
39 | darkModeSwitch = findViewById(R.id.dark_mode_switch);
40 |
41 | // Initialize Firebase Auth
42 | mAuth = FirebaseAuth.getInstance();
43 |
44 | // Initialize SharedPreferences for dark mode
45 | sharedPreferences = getSharedPreferences("MyPrefs", MODE_PRIVATE);
46 | editor = sharedPreferences.edit();
47 |
48 | // Check current dark mode status and set the switch accordingly
49 | boolean isDarkModeOn = sharedPreferences.getBoolean("isDarkModeOn", false);
50 | darkModeSwitch.setChecked(isDarkModeOn);
51 |
52 | // Apply the dark mode if it's enabled
53 | if (isDarkModeOn) {
54 | AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
55 | } else {
56 | AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
57 | }
58 |
59 | // Set the dark mode toggle listener
60 | darkModeSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> {
61 | if (isChecked) {
62 | // Enable dark mode and save preference
63 | AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
64 | editor.putBoolean("isDarkModeOn", true);
65 | } else {
66 | // Disable dark mode and save preference
67 | AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
68 | editor.putBoolean("isDarkModeOn", false);
69 | }
70 | editor.apply();
71 | });
72 |
73 | // Logout event listener
74 | buttonLogout.setOnClickListener(view -> logoutUser());
75 |
76 | // Click event listener for add task button
77 | addTaskButton.setOnClickListener(view -> loadFragment(new AddTaskFragment()));
78 |
79 | // Click event listener for view task button
80 | viewTaskButton.setOnClickListener(view -> loadFragment(new ViewTasksFragment()));
81 |
82 | ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.menu), (v, insets) -> {
83 | Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
84 | v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
85 | return insets;
86 | });
87 | }
88 |
89 | // Method to load specified fragment into fragment_container
90 | private void loadFragment(Fragment fragment) {
91 | FragmentManager fragmentManager = getSupportFragmentManager();
92 | FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
93 | fragmentTransaction.replace(R.id.fragment_container, fragment);
94 | fragmentTransaction.addToBackStack(null); // Optional: add this transaction to the back stack
95 | fragmentTransaction.commit();
96 | }
97 |
98 | // LOG OUT METHOD
99 | private void logoutUser() {
100 | mAuth.signOut(); // Sign out from Firebase
101 | Intent intent = new Intent(MenuActivity.this, MainActivity.class);
102 | intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
103 | startActivity(intent);
104 | finish();
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/to_do_app/RegistrationActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.to_do_app;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.view.View;
6 | import android.widget.Button;
7 | import android.widget.EditText;
8 | import android.widget.Toast;
9 |
10 | import androidx.activity.EdgeToEdge;
11 | import androidx.appcompat.app.AppCompatActivity;
12 | import androidx.core.graphics.Insets;
13 | import androidx.core.view.ViewCompat;
14 | import androidx.core.view.WindowInsetsCompat;
15 |
16 | import com.google.firebase.FirebaseApp;
17 | import com.google.firebase.firestore.FirebaseFirestore;
18 | import com.google.firebase.firestore.QueryDocumentSnapshot;
19 | import com.google.firebase.firestore.QuerySnapshot;
20 | import com.google.firebase.auth.FirebaseAuth;
21 | import com.google.firebase.auth.FirebaseUser;
22 |
23 | import java.util.Objects;
24 |
25 | public class RegistrationActivity extends AppCompatActivity {
26 |
27 | private EditText editTextEmail;
28 | private EditText editTextPassword;
29 | private EditText editTextPassConfirm;
30 | private Button buttonRegister;
31 | private FirebaseAuth mAuth;
32 | private FirebaseUser user;
33 |
34 | @Override
35 | protected void onCreate(Bundle savedInstanceState) {
36 | super.onCreate(savedInstanceState);
37 | setContentView(R.layout.register_popup);
38 |
39 | mAuth = FirebaseAuth.getInstance();
40 | buttonRegister = findViewById(R.id.btnRegister);
41 | editTextEmail = findViewById(R.id.emailRegistration);
42 | editTextPassword = findViewById(R.id.passwordRegistration);
43 | editTextPassConfirm = findViewById(R.id.confirmPassRegistration);
44 |
45 | buttonRegister.setOnClickListener(new View.OnClickListener() {
46 | @Override
47 | public void onClick(View v) {
48 | Intent intent = new Intent(RegistrationActivity.this, RegistrationActivity.class);
49 | String email = editTextEmail.getText().toString().trim();
50 | String password = editTextPassword.getText().toString().trim();
51 | String confirmPass = editTextPassConfirm.getText().toString().trim();
52 | // Check for required fields/format
53 | if (email.isEmpty()) {
54 | editTextEmail.setError("Email is required");
55 | editTextEmail.requestFocus();
56 | return;
57 | }
58 |
59 | if (password.isEmpty()) {
60 | editTextPassword.setError("Password is required");
61 | editTextPassword.requestFocus();
62 | return;
63 | }
64 | if (!confirmPass.equals(password)) {
65 | editTextPassConfirm.setError("Passwords do not match");
66 | return;
67 | }
68 | // Call method with email and password entered as parameters to authenticate user's registration
69 | registerUser(email, password);
70 | }
71 | });
72 |
73 | }
74 | // REGISTER AUTH -- email and password as parameters to register
75 | private void registerUser(String email, String password) {
76 | mAuth.createUserWithEmailAndPassword(email, password).addOnCompleteListener(this, task -> {
77 | if (task.isSuccessful()) { // If registration is successful
78 | FirebaseUser user = mAuth.getCurrentUser();
79 | if (user != null) {
80 | user.sendEmailVerification().addOnCompleteListener(emailTask -> {
81 | if (emailTask.isSuccessful()) {
82 | Toast.makeText(RegistrationActivity.this, "Registration successful! Please check your email for verification.", Toast.LENGTH_LONG).show();
83 | }
84 | else {
85 | Toast.makeText(RegistrationActivity.this, "Failed to send email.", Toast.LENGTH_SHORT).show();
86 | }
87 | });
88 | }
89 |
90 | // Then take user to Login activity
91 | Intent intent = new Intent(RegistrationActivity.this, MainActivity.class);
92 | startActivity(intent);
93 | finish();
94 | } else {
95 | Toast.makeText(RegistrationActivity.this, "Registration failed: " + Objects.requireNonNull(task.getException()).getMessage(), Toast.LENGTH_SHORT).show();
96 | }
97 | });
98 | }
99 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/to_do_app/Task.java:
--------------------------------------------------------------------------------
1 | package com.example.to_do_app;
2 |
3 | import com.google.firebase.Timestamp;
4 |
5 | public class Task {
6 | // Fields
7 | private String id;
8 | private String title;
9 | private String description;
10 | private Timestamp dueDate; // New field for due date
11 | private Integer importance; // New field for importance level (1 to 5)
12 |
13 | // Default constructor for DataSnapshot.getValue(Task.class)
14 | public Task() {
15 | }
16 |
17 | // Parameterized Constructor
18 | public Task(String id, String title, String description, Timestamp dueDate, int importance) {
19 | this.id = id;
20 | this.title = title;
21 | this.description = description;
22 | this.dueDate = dueDate; // Initialize the due date
23 | this.importance = importance;
24 | }
25 |
26 | // Getters and Setters for task id, title, description, dueDate
27 | public String getId() {
28 | return id;
29 | }
30 |
31 | public void setId(String id) {
32 | this.id = id;
33 | }
34 |
35 | public String getTitle() {
36 | return title;
37 | }
38 |
39 | public void setTitle(String title) {
40 | this.title = title;
41 | }
42 |
43 | public String getDescription() {
44 | return description;
45 | }
46 |
47 | public void setDescription(String description) {
48 | this.description = description;
49 | }
50 |
51 | public Timestamp getDueDate() {
52 | return dueDate;
53 | }
54 |
55 | public void setDueDate(Timestamp dueDate) {
56 | this.dueDate = dueDate;
57 | }
58 |
59 | public Integer getImportance() {
60 | return importance;
61 | }
62 | public void setImportance(int importance) { this.importance = importance; }
63 | }
64 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/to_do_app/ViewTasksFragment.java:
--------------------------------------------------------------------------------
1 | package com.example.to_do_app;
2 |
3 | import android.app.AlertDialog;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 | import androidx.fragment.app.Fragment;
7 | import android.view.LayoutInflater;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 | import android.widget.ImageButton;
11 | import android.widget.LinearLayout;
12 | import android.widget.TextView;
13 | import android.widget.Toast;
14 | import com.google.firebase.auth.FirebaseAuth;
15 | import com.google.firebase.auth.FirebaseUser;
16 | import com.google.firebase.firestore.FirebaseFirestore;
17 | import com.google.firebase.firestore.QueryDocumentSnapshot;
18 | import java.text.SimpleDateFormat;
19 | import java.util.Locale;
20 | import androidx.annotation.NonNull;
21 | import androidx.annotation.Nullable;
22 |
23 | public class ViewTasksFragment extends Fragment {
24 | private LinearLayout linearLayoutTasks;
25 | private FirebaseFirestore db;
26 |
27 | private static final String ARG_PARAM1 = "param1";
28 | private static final String ARG_PARAM2 = "param2";
29 | private String mParam1;
30 | private String mParam2;
31 |
32 | public ViewTasksFragment() {
33 | // Required empty public constructor
34 | }
35 |
36 | public static ViewTasksFragment newInstance(String param1, String param2) {
37 | ViewTasksFragment fragment = new ViewTasksFragment();
38 | Bundle args = new Bundle();
39 | args.putString(ARG_PARAM1, param1);
40 | args.putString(ARG_PARAM2, param2);
41 | fragment.setArguments(args);
42 | return fragment;
43 | }
44 |
45 | @Override
46 | public void onCreate(Bundle savedInstanceState) {
47 | super.onCreate(savedInstanceState);
48 | if (getArguments() != null) {
49 | mParam1 = getArguments().getString(ARG_PARAM1);
50 | mParam2 = getArguments().getString(ARG_PARAM2);
51 | }
52 | }
53 |
54 | @Nullable
55 | @Override
56 | public View onCreateView(@NonNull LayoutInflater inflater,@Nullable ViewGroup container,
57 | Bundle savedInstanceState) {
58 | View view = inflater.inflate(R.layout.fragment_view_tasks, container, false);
59 | db = FirebaseFirestore.getInstance();
60 | linearLayoutTasks = view.findViewById(R.id.linearLayoutTasks);
61 | loadTasks();
62 | return view;
63 | }
64 |
65 | private void loadTasks() {
66 | FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
67 | if (user == null) {
68 | Toast.makeText(getActivity(), "User not authenticated", Toast.LENGTH_SHORT).show();
69 | return;
70 | }
71 |
72 | db.collection("users").document(user.getUid()).collection("tasks").orderBy("timestamp").get().addOnCompleteListener(task -> {
73 | if (task.isSuccessful()) {
74 | linearLayoutTasks.removeAllViews();
75 | for (QueryDocumentSnapshot document : task.getResult()) {
76 | Task taskObj = document.toObject(Task.class);
77 |
78 | View taskCardView = LayoutInflater.from(getActivity()).inflate(R.layout.item_task_card, linearLayoutTasks, false);
79 |
80 | TextView taskTitleTextView = taskCardView.findViewById(R.id.textViewTitle);
81 | TextView taskDescriptionTextView = taskCardView.findViewById(R.id.textViewDescription);
82 | TextView taskDueDateTextView = taskCardView.findViewById(R.id.textViewDueDate);
83 | TextView taskImportanceTextView = taskCardView.findViewById(R.id.textViewImportance);
84 |
85 | ImageButton editButton = taskCardView.findViewById(R.id.buttonEditTask);
86 | ImageButton deleteButton = taskCardView.findViewById(R.id.buttonDeleteTask);
87 |
88 | // Set task details
89 | taskTitleTextView.setText(taskObj.getTitle());
90 | taskDescriptionTextView.setText(taskObj.getDescription());
91 |
92 | // Format the due date
93 | SimpleDateFormat sdf = new SimpleDateFormat("MMM dd, yyyy", Locale.getDefault());
94 | if (taskObj.getDueDate() != null) {
95 | taskDueDateTextView.setText("Due: " + sdf.format(taskObj.getDueDate().toDate()));
96 | } else {
97 | taskDueDateTextView.setText("Due: Not set");
98 | }
99 |
100 | // Apply color-coded importance level
101 | if (taskObj.getImportance() != null) {
102 | switch (taskObj.getImportance()) {
103 | case 0: // Low importance
104 | taskImportanceTextView.setText("Importance: Low");
105 | taskImportanceTextView.setTextColor(getResources().getColor(R.color.importanceLow)); // Green
106 | break;
107 | case 1: // Medium importance
108 | taskImportanceTextView.setText("Importance: Medium");
109 | taskImportanceTextView.setTextColor(getResources().getColor(R.color.importanceMedium)); // Yellow
110 | break;
111 | case 2: // High importance
112 | taskImportanceTextView.setText("Importance: High");
113 | taskImportanceTextView.setTextColor(getResources().getColor(R.color.importanceHigh)); // Red
114 | break;
115 | default:
116 | taskImportanceTextView.setText("Importance: Not set");
117 | taskImportanceTextView.setTextColor(getResources().getColor(R.color.black)); // Default to black
118 | }
119 | } else {
120 | taskImportanceTextView.setText("Importance: Not set");
121 | taskImportanceTextView.setTextColor(getResources().getColor(R.color.black)); // Default to black
122 | }
123 |
124 | // Set edit and delete functionality
125 | editButton.setOnClickListener(v -> {
126 | Intent intent = new Intent(getActivity(), EditTaskActivity.class);
127 | intent.putExtra("taskId", taskObj.getId());
128 | intent.putExtra("taskTitle", taskObj.getTitle());
129 | intent.putExtra("taskDescription", taskObj.getDescription());
130 | intent.putExtra("taskDueDate", taskObj.getDueDate());
131 | startActivity(intent);
132 | });
133 |
134 | deleteButton.setOnClickListener(v -> confirmDeleteTask(taskObj.getId()));
135 |
136 | linearLayoutTasks.addView(taskCardView);
137 | }
138 | }
139 | });
140 | }
141 |
142 | void deleteTask(String taskId) {
143 | FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
144 | if (user != null) {
145 | db.collection("users").document(user.getUid()).collection("tasks").document(taskId)
146 | .delete()
147 | .addOnSuccessListener(aVoid -> {
148 | Toast.makeText(getActivity(), "Task deleted", Toast.LENGTH_SHORT).show();
149 | loadTasks();
150 | onResume();
151 | })
152 | .addOnFailureListener(e -> {
153 | Toast.makeText(getActivity(), "Error deleting task", Toast.LENGTH_SHORT).show();
154 | });
155 | }
156 | }
157 |
158 | private void confirmDeleteTask(String taskId) {
159 | new AlertDialog.Builder(getActivity())
160 | .setTitle("Delete Task")
161 | .setMessage("Are you sure you want to delete this task?")
162 | .setPositiveButton("Yes", (dialog, which) -> deleteTask(taskId))
163 | .setNegativeButton("No", null)
164 | .show();
165 | }
166 |
167 | @Override
168 | public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
169 | super.onViewCreated(view, savedInstanceState);
170 | loadTasks();
171 | }
172 |
173 | @Override
174 | public void onResume() {
175 | super.onResume();
176 | linearLayoutTasks.removeAllViews();
177 | loadTasks();
178 | }
179 | }
180 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-nodpi/ocean_blue_copy_space_abstract_paper_waves.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hieudku/TasksManagementApp--Android-Java-Firebase/84e91b106e4ddbd20f3068fefaac3dfe6117983a/app/src/main/res/drawable-nodpi/ocean_blue_copy_space_abstract_paper_waves.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable/baseline_delete_24.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/baseline_edit_24.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icons8_wave_96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hieudku/TasksManagementApp--Android-Java-Firebase/84e91b106e4ddbd20f3068fefaac3dfe6117983a/app/src/main/res/drawable/icons8_wave_96.png
--------------------------------------------------------------------------------
/app/src/main/res/font/oxygen.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/font/oxygen_bold.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/font/oxygen_light.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hieudku/TasksManagementApp--Android-Java-Firebase/84e91b106e4ddbd20f3068fefaac3dfe6117983a/app/src/main/res/font/oxygen_light.ttf
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_edit_task.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
18 |
19 |
26 |
27 |
33 |
34 |
38 |
43 |
44 |
53 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
20 |
21 |
26 |
27 |
34 |
35 |
36 |
37 |
47 |
48 |
59 |
60 |
69 |
70 |
79 |
80 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
21 |
22 |
28 |
29 |
39 |
40 |
50 |
51 |
60 |
61 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_add_task.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
14 |
21 |
22 |
23 |
33 |
34 |
35 |
36 |
42 |
46 |
51 |
52 |
60 |
61 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_view_tasks.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
12 |
17 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_task_card.xml:
--------------------------------------------------------------------------------
1 |
11 |
12 |
17 |
18 |
19 |
27 |
28 |
29 |
37 |
38 |
45 |
51 |
52 |
58 |
59 |
60 |
61 |
69 |
70 |
71 |
80 |
81 |
82 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/register_popup.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
15 |
16 |
22 |
23 |
29 |
30 |
36 |
37 |
44 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hieudku/TasksManagementApp--Android-Java-Firebase/84e91b106e4ddbd20f3068fefaac3dfe6117983a/app/src/main/res/mipmap-hdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hieudku/TasksManagementApp--Android-Java-Firebase/84e91b106e4ddbd20f3068fefaac3dfe6117983a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hieudku/TasksManagementApp--Android-Java-Firebase/84e91b106e4ddbd20f3068fefaac3dfe6117983a/app/src/main/res/mipmap-mdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hieudku/TasksManagementApp--Android-Java-Firebase/84e91b106e4ddbd20f3068fefaac3dfe6117983a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hieudku/TasksManagementApp--Android-Java-Firebase/84e91b106e4ddbd20f3068fefaac3dfe6117983a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hieudku/TasksManagementApp--Android-Java-Firebase/84e91b106e4ddbd20f3068fefaac3dfe6117983a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hieudku/TasksManagementApp--Android-Java-Firebase/84e91b106e4ddbd20f3068fefaac3dfe6117983a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hieudku/TasksManagementApp--Android-Java-Firebase/84e91b106e4ddbd20f3068fefaac3dfe6117983a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hieudku/TasksManagementApp--Android-Java-Firebase/84e91b106e4ddbd20f3068fefaac3dfe6117983a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hieudku/TasksManagementApp--Android-Java-Firebase/84e91b106e4ddbd20f3068fefaac3dfe6117983a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/values-night/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #BB86FC
4 | #3700B3
5 | #03DAC5
6 |
7 | #121212
8 | #FFFFFF
9 | #BB86FC
10 | #CF6679
11 |
12 | #121212
13 | #FFFFFF
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/values-night/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/values-night/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FF000000
4 | #FFFFFFFF
5 | #172812
6 | #BCB195
7 | #230230
8 | #D3D3D3
9 | #484030
10 | #F6F0E1
11 | #E9967A
12 | #008080
13 | #800000
14 | #228B22
15 |
16 | #FFFFFF
17 | #000000
18 | #03DAC5
19 | #B00020
20 | #6200EE
21 | #3700B3
22 | #03DAC5
23 |
24 | #FFFFFF
25 | #000000
26 |
27 |
28 | #4CAF50
29 | #FFC107
30 | #F44336
31 |
--------------------------------------------------------------------------------
/app/src/main/res/values/font_certs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | - @array/com_google_android_gms_fonts_certs_dev
5 | - @array/com_google_android_gms_fonts_certs_prod
6 |
7 |
8 | -
9 | MIIEqDCCA5CgAwIBAgIJANWFuGx90071MA0GCSqGSIb3DQEBBAUAMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAeFw0wODA0MTUyMzM2NTZaFw0zNTA5MDEyMzM2NTZaMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBANbOLggKv+IxTdGNs8/TGFy0PTP6DHThvbbR24kT9ixcOd9W+EaBPWW+wPPKQmsHxajtWjmQwWfna8mZuSeJS48LIgAZlKkpFeVyxW0qMBujb8X8ETrWy550NaFtI6t9+u7hZeTfHwqNvacKhp1RbE6dBRGWynwMVX8XW8N1+UjFaq6GCJukT4qmpN2afb8sCjUigq0GuMwYXrFVee74bQgLHWGJwPmvmLHC69EH6kWr22ijx4OKXlSIx2xT1AsSHee70w5iDBiK4aph27yH3TxkXy9V89TDdexAcKk/cVHYNnDBapcavl7y0RiQ4biu8ymM8Ga/nmzhRKya6G0cGw8CAQOjgfwwgfkwHQYDVR0OBBYEFI0cxb6VTEM8YYY6FbBMvAPyT+CyMIHJBgNVHSMEgcEwgb6AFI0cxb6VTEM8YYY6FbBMvAPyT+CyoYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJANWFuGx90071MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADggEBABnTDPEF+3iSP0wNfdIjIz1AlnrPzgAIHVvXxunW7SBrDhEglQZBbKJEk5kT0mtKoOD1JMrSu1xuTKEBahWRbqHsXclaXjoBADb0kkjVEJu/Lh5hgYZnOjvlba8Ld7HCKePCVePoTJBdI4fvugnL8TsgK05aIskyY0hKI9L8KfqfGTl1lzOv2KoWD0KWwtAWPoGChZxmQ+nBli+gwYMzM1vAkP+aayLe0a1EQimlOalO762r0GXO0ks+UeXde2Z4e+8S/pf7pITEI/tP+MxJTALw9QUWEv9lKTk+jkbqxbsh8nfBUapfKqYn0eidpwq2AzVp3juYl7//fKnaPhJD9gs=
10 |
11 |
12 |
13 | -
14 | MIIEQzCCAyugAwIBAgIJAMLgh0ZkSjCNMA0GCSqGSIb3DQEBBAUAMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDAeFw0wODA4MjEyMzEzMzRaFw0zNjAxMDcyMzEzMzRaMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBAKtWLgDYO6IIrgqWbxJOKdoR8qtW0I9Y4sypEwPpt1TTcvZApxsdyxMJZ2JORland2qSGT2y5b+3JKkedxiLDmpHpDsz2WCbdxgxRczfey5YZnTJ4VZbH0xqWVW/8lGmPav5xVwnIiJS6HXk+BVKZF+JcWjAsb/GEuq/eFdpuzSqeYTcfi6idkyugwfYwXFU1+5fZKUaRKYCwkkFQVfcAs1fXA5V+++FGfvjJ/CxURaSxaBvGdGDhfXE28LWuT9ozCl5xw4Yq5OGazvV24mZVSoOO0yZ31j7kYvtwYK6NeADwbSxDdJEqO4k//0zOHKrUiGYXtqw/A0LFFtqoZKFjnkCAQOjgdkwgdYwHQYDVR0OBBYEFMd9jMIhF1Ylmn/Tgt9r45jk14alMIGmBgNVHSMEgZ4wgZuAFMd9jMIhF1Ylmn/Tgt9r45jk14aloXikdjB0MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLR29vZ2xlIEluYy4xEDAOBgNVBAsTB0FuZHJvaWQxEDAOBgNVBAMTB0FuZHJvaWSCCQDC4IdGZEowjTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBAUAA4IBAQBt0lLO74UwLDYKqs6Tm8/yzKkEu116FmH4rkaymUIE0P9KaMftGlMexFlaYjzmB2OxZyl6euNXEsQH8gjwyxCUKRJNexBiGcCEyj6z+a1fuHHvkiaai+KL8W1EyNmgjmyy8AW7P+LLlkR+ho5zEHatRbM/YAnqGcFh5iZBqpknHf1SKMXFh4dd239FJ1jWYfbMDMy3NS5CTMQ2XFI1MvcyUTdZPErjQfTbQe3aDQsQcafEQPD+nqActifKZ0Np0IS9L9kR/wbNvyz6ENwPiTrjV2KRkEjH78ZMcUQXg0L3BYHJ3lc69Vs5Ddf9uUGGMYldX3WfMBEmh/9iFBDAaTCK
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/values/preloaded_fonts.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | - @font/oxygen
5 | - @font/oxygen_bold
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | To-do-app
3 | Username
4 | Password
5 | Login
6 | Register
7 | Add Task
8 | View Tasks
9 | Task Name
10 | Task Description
11 | Save Task
12 |
13 | Hello blank fragment
14 | Task Description
15 | Task Name
16 | Add
17 | Email
18 | Log out
19 | Tasks will be listed here
20 | Remindo
21 | Task Title
22 | Task Description
23 | Task Title
24 | My Tasks
25 | Edit Task
26 | Delete Task
27 | Task Title
28 | Task Description
29 | Update Task
30 | TaskFlo
31 | Email
32 | Password
33 | Confirm password
34 | Register
35 | Create an account
36 |
37 |
38 | - Low
39 | - Medium
40 | - High
41 |
42 |
43 |
44 | - Sort by Due Date
45 | - Sort by Importance
46 |
47 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/backup_rules.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/data_extraction_rules.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
12 |
13 |
19 |
--------------------------------------------------------------------------------
/app/src/test/java/com/example/to_do_app/AddTaskFragmentTest.java:
--------------------------------------------------------------------------------
1 | package com.example.to_do_app;
2 |
3 | import com.google.firebase.Timestamp;
4 | import org.junit.Test;
5 |
6 | import java.util.Date;
7 | import java.util.HashMap;
8 | import java.util.Map;
9 |
10 | import static org.junit.Assert.assertEquals;
11 | import static org.junit.Assert.assertNull;
12 | import static org.junit.Assert.assertTrue;
13 |
14 | public class AddTaskFragmentTest {
15 |
16 | public Map createTaskMap(String title, String description, Date dueDate) {
17 | Map task = new HashMap<>();
18 | task.put("title", title);
19 | task.put("description", description);
20 | if (dueDate != null) {
21 | task.put("dueDate", new Timestamp(dueDate));
22 | }
23 | task.put("timestamp", new Timestamp(new Date()));
24 | return task;
25 | }
26 |
27 | @Test
28 | public void testCreateTaskMap() {
29 | // TC_ADD_01: Test Save Task with Valid Input
30 |
31 | // Arrange
32 | String title = "Test Task";
33 | String description = "Test Description";
34 | Date dueDate = new Date(2024 - 1900, 8, 17); // September 17, 2024
35 |
36 | // Act
37 | Map taskMap = createTaskMap(title, description, dueDate);
38 |
39 | // Assert
40 | assertEquals("Test Task", taskMap.get("title"));
41 | assertEquals("Test Description", taskMap.get("description"));
42 | assertTrue(taskMap.get("dueDate") instanceof Timestamp);
43 | assertTrue(taskMap.get("timestamp") instanceof Timestamp);
44 | }
45 |
46 | @Test
47 | public void testCreateTaskMapWithEmptyTitle() {
48 | // TC_ADD_02: Test Save Task with Empty Title
49 |
50 | // Arrange
51 | String title = ""; // Empty title
52 | String description = "Test Description";
53 | Date dueDate = new Date(2024 - 1900, 8, 17); // September 17, 2024
54 |
55 | // Act
56 | Map taskMap = createTaskMap(title, description, dueDate);
57 |
58 | // Assert
59 | assertEquals("", taskMap.get("title"));
60 | assertEquals("Test Description", taskMap.get("description"));
61 | assertTrue(taskMap.get("dueDate") instanceof Timestamp);
62 | }
63 |
64 | @Test
65 | public void testCreateTaskMapWithoutDueDate() {
66 | // TC_ADD_03: Test Save Task Without Date
67 |
68 | // Arrange
69 | String title = "Test Task";
70 | String description = "Test Description";
71 |
72 | // Act
73 | Map taskMap = createTaskMap(title, description, null);
74 |
75 | // Assert
76 | assertEquals("Test Task", taskMap.get("title"));
77 | assertEquals("Test Description", taskMap.get("description"));
78 | assertNull(taskMap.get("dueDate")); // Due date should be null
79 | assertTrue(taskMap.get("timestamp") instanceof Timestamp);
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/app/src/test/java/com/example/to_do_app/ViewTasksFragmentTest.java:
--------------------------------------------------------------------------------
1 | package com.example.to_do_app;
2 |
3 | import com.google.firebase.Timestamp;
4 | import junit.framework.TestCase;
5 | import java.text.SimpleDateFormat;
6 | import java.util.Date;
7 | import java.util.Locale;
8 | import java.util.Map;
9 | import java.util.HashMap;
10 |
11 | public class ViewTasksFragmentTest extends TestCase {
12 |
13 | private ViewTasksFragment fragment;
14 |
15 | public void setUp() throws Exception {
16 | super.setUp();
17 | fragment = new ViewTasksFragment();
18 | }
19 |
20 | public void tearDown() throws Exception {
21 | fragment = null;
22 | }
23 |
24 | // Utility method to test date formatting
25 | private String formatTaskDueDate(Timestamp dueDate) {
26 | if (dueDate == null) {
27 | return "Due: Not set";
28 | }
29 | SimpleDateFormat sdf = new SimpleDateFormat("MMM dd, yyyy", Locale.getDefault());
30 | return "Due: " + sdf.format(dueDate.toDate());
31 | }
32 |
33 | public void testFormatTaskDueDate() {
34 | // TC_VIEW_01: Test Load Tasks - Correct date formatting
35 |
36 | // Arrange
37 | Date date = new Date(2024 - 1900, 8, 17); // September 17, 2024
38 | Timestamp timestamp = new Timestamp(date);
39 |
40 | // Act
41 | String formattedDate = formatTaskDueDate(timestamp);
42 |
43 | // Assert
44 | assertEquals("Due: Sep 17, 2024", formattedDate);
45 | }
46 |
47 | public void testFormatTaskDueDateWithNull() {
48 | // TC_VIEW_02: Test Load Tasks with Missing Due Date
49 |
50 | // Act
51 | String formattedDate = formatTaskDueDate(null);
52 |
53 | // Assert
54 | assertEquals("Due: Not set", formattedDate);
55 | }
56 |
57 | public void testLoadTasks() {
58 | // TC_VIEW_01: Test Load Tasks - Correct loading and display of tasks
59 |
60 | // Arrange
61 | Map taskMap = new HashMap<>();
62 | taskMap.put("title", "Test Task");
63 | taskMap.put("description", "Test Description");
64 | taskMap.put("dueDate", new Timestamp(new Date(2024 - 1900, 8, 17)));
65 |
66 | // Act
67 | String formattedDate = formatTaskDueDate((Timestamp) taskMap.get("dueDate"));
68 |
69 | // Assert
70 | assertEquals("Due: Sep 17, 2024", formattedDate);
71 | assertEquals("Test Task", taskMap.get("title"));
72 | assertEquals("Test Description", taskMap.get("description"));
73 | }
74 |
75 | public void testEditTaskNavigation() {
76 | // TC_VIEW_04: Test Edit Task Navigation
77 |
78 | // Arrange
79 | Map taskMap = new HashMap<>();
80 | taskMap.put("id", "task123");
81 | taskMap.put("title", "Task to be edited");
82 | taskMap.put("description", "Edit this description");
83 | taskMap.put("dueDate", new Timestamp(new Date(2024 - 1900, 8, 17)));
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/build.gradle.kts:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | plugins {
3 | alias(libs.plugins.android.application) apply false
4 |
5 | // Dependency for the Google services Gradle plugin
6 | id("com.google.gms.google-services") version "4.4.2" apply false;
7 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. For more details, visit
12 | # https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app's APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Enables namespacing of each library's R class so that its R class includes only the
19 | # resources declared in the library itself and none from the library's dependencies,
20 | # thereby reducing the size of the R class for that library
21 | android.nonTransitiveRClass=true
--------------------------------------------------------------------------------
/gradle/libs.versions.toml:
--------------------------------------------------------------------------------
1 | [versions]
2 | agp = "8.5.0"
3 | junit = "4.13.2"
4 | junitVersion = "1.2.1"
5 | espressoCore = "3.6.1"
6 | appcompat = "1.6.1"
7 | material = "1.10.0"
8 | activity = "1.9.0"
9 | constraintlayout = "2.1.4"
10 |
11 | [libraries]
12 | junit = { group = "junit", name = "junit", version.ref = "junit" }
13 | ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
14 | espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
15 | appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
16 | material = { group = "com.google.android.material", name = "material", version.ref = "material" }
17 | activity = { group = "androidx.activity", name = "activity", version.ref = "activity" }
18 | constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" }
19 |
20 | [plugins]
21 | android-application = { id = "com.android.application", version.ref = "agp" }
22 |
23 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hieudku/TasksManagementApp--Android-Java-Firebase/84e91b106e4ddbd20f3068fefaac3dfe6117983a/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Aug 09 13:30:47 NZST 2024
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
5 | zipStoreBase=GRADLE_USER_HOME
6 | zipStorePath=wrapper/dists
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 |
86 | # Determine the Java command to use to start the JVM.
87 | if [ -n "$JAVA_HOME" ] ; then
88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
89 | # IBM's JDK on AIX uses strange locations for the executables
90 | JAVACMD="$JAVA_HOME/jre/sh/java"
91 | else
92 | JAVACMD="$JAVA_HOME/bin/java"
93 | fi
94 | if [ ! -x "$JAVACMD" ] ; then
95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
96 |
97 | Please set the JAVA_HOME variable in your environment to match the
98 | location of your Java installation."
99 | fi
100 | else
101 | JAVACMD="java"
102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
103 |
104 | Please set the JAVA_HOME variable in your environment to match the
105 | location of your Java installation."
106 | fi
107 |
108 | # Increase the maximum file descriptors if we can.
109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
110 | MAX_FD_LIMIT=`ulimit -H -n`
111 | if [ $? -eq 0 ] ; then
112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
113 | MAX_FD="$MAX_FD_LIMIT"
114 | fi
115 | ulimit -n $MAX_FD
116 | if [ $? -ne 0 ] ; then
117 | warn "Could not set maximum file descriptor limit: $MAX_FD"
118 | fi
119 | else
120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
121 | fi
122 | fi
123 |
124 | # For Darwin, add options to specify how the application appears in the dock
125 | if $darwin; then
126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
127 | fi
128 |
129 | # For Cygwin or MSYS, switch paths to Windows format before running java
130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
133 |
134 | JAVACMD=`cygpath --unix "$JAVACMD"`
135 |
136 | # We build the pattern for arguments to be converted via cygpath
137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
138 | SEP=""
139 | for dir in $ROOTDIRSRAW ; do
140 | ROOTDIRS="$ROOTDIRS$SEP$dir"
141 | SEP="|"
142 | done
143 | OURCYGPATTERN="(^($ROOTDIRS))"
144 | # Add a user-defined pattern to the cygpath arguments
145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
147 | fi
148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
149 | i=0
150 | for arg in "$@" ; do
151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
153 |
154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
156 | else
157 | eval `echo args$i`="\"$arg\""
158 | fi
159 | i=`expr $i + 1`
160 | done
161 | case $i in
162 | 0) set -- ;;
163 | 1) set -- "$args0" ;;
164 | 2) set -- "$args0" "$args1" ;;
165 | 3) set -- "$args0" "$args1" "$args2" ;;
166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
172 | esac
173 | fi
174 |
175 | # Escape application args
176 | save () {
177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
178 | echo " "
179 | }
180 | APP_ARGS=`save "$@"`
181 |
182 | # Collect all arguments for the java command, following the shell quoting and substitution rules
183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
184 |
185 | exec "$JAVACMD" "$@"
186 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | google {
4 | content {
5 | includeGroupByRegex("com\\.android.*")
6 | includeGroupByRegex("com\\.google.*")
7 | includeGroupByRegex("androidx.*")
8 | }
9 | }
10 | mavenCentral()
11 | gradlePluginPortal()
12 | }
13 | }
14 | dependencyResolutionManagement {
15 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
16 | repositories {
17 | google()
18 | mavenCentral()
19 | }
20 | }
21 |
22 | rootProject.name = "To-do-app"
23 | include(":app")
24 |
--------------------------------------------------------------------------------
/v0.2.0_Screenshot_Pixel8Pro/AddTask.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hieudku/TasksManagementApp--Android-Java-Firebase/84e91b106e4ddbd20f3068fefaac3dfe6117983a/v0.2.0_Screenshot_Pixel8Pro/AddTask.jpg
--------------------------------------------------------------------------------
/v0.2.0_Screenshot_Pixel8Pro/AddTaskWImportance-Dark.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hieudku/TasksManagementApp--Android-Java-Firebase/84e91b106e4ddbd20f3068fefaac3dfe6117983a/v0.2.0_Screenshot_Pixel8Pro/AddTaskWImportance-Dark.jpg
--------------------------------------------------------------------------------
/v0.2.0_Screenshot_Pixel8Pro/Firestore.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hieudku/TasksManagementApp--Android-Java-Firebase/84e91b106e4ddbd20f3068fefaac3dfe6117983a/v0.2.0_Screenshot_Pixel8Pro/Firestore.jpg
--------------------------------------------------------------------------------
/v0.2.0_Screenshot_Pixel8Pro/Importance.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hieudku/TasksManagementApp--Android-Java-Firebase/84e91b106e4ddbd20f3068fefaac3dfe6117983a/v0.2.0_Screenshot_Pixel8Pro/Importance.jpg
--------------------------------------------------------------------------------
/v0.2.0_Screenshot_Pixel8Pro/UpdateTask.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hieudku/TasksManagementApp--Android-Java-Firebase/84e91b106e4ddbd20f3068fefaac3dfe6117983a/v0.2.0_Screenshot_Pixel8Pro/UpdateTask.jpg
--------------------------------------------------------------------------------
/v0.2.0_Screenshot_Pixel8Pro/ViewTasks.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hieudku/TasksManagementApp--Android-Java-Firebase/84e91b106e4ddbd20f3068fefaac3dfe6117983a/v0.2.0_Screenshot_Pixel8Pro/ViewTasks.jpg
--------------------------------------------------------------------------------
/v0.2.0_Screenshot_Pixel8Pro/ViewTasksWImportance-Dark.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hieudku/TasksManagementApp--Android-Java-Firebase/84e91b106e4ddbd20f3068fefaac3dfe6117983a/v0.2.0_Screenshot_Pixel8Pro/ViewTasksWImportance-Dark.jpg
--------------------------------------------------------------------------------
/v0.2.0_Screenshot_Pixel8Pro/v0.2.0_Add_task_frag.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hieudku/TasksManagementApp--Android-Java-Firebase/84e91b106e4ddbd20f3068fefaac3dfe6117983a/v0.2.0_Screenshot_Pixel8Pro/v0.2.0_Add_task_frag.png
--------------------------------------------------------------------------------
/v0.2.0_Screenshot_Pixel8Pro/v0.2.0_Firestore_db.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hieudku/TasksManagementApp--Android-Java-Firebase/84e91b106e4ddbd20f3068fefaac3dfe6117983a/v0.2.0_Screenshot_Pixel8Pro/v0.2.0_Firestore_db.jpg
--------------------------------------------------------------------------------
/v0.2.0_Screenshot_Pixel8Pro/v0.2.0_Main_login_screen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hieudku/TasksManagementApp--Android-Java-Firebase/84e91b106e4ddbd20f3068fefaac3dfe6117983a/v0.2.0_Screenshot_Pixel8Pro/v0.2.0_Main_login_screen.png
--------------------------------------------------------------------------------
/v0.2.0_Screenshot_Pixel8Pro/v0.2.0_Menu_add_view_logout.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hieudku/TasksManagementApp--Android-Java-Firebase/84e91b106e4ddbd20f3068fefaac3dfe6117983a/v0.2.0_Screenshot_Pixel8Pro/v0.2.0_Menu_add_view_logout.png
--------------------------------------------------------------------------------
/v0.2.0_Screenshot_Pixel8Pro/v0.2.0_Update_task.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hieudku/TasksManagementApp--Android-Java-Firebase/84e91b106e4ddbd20f3068fefaac3dfe6117983a/v0.2.0_Screenshot_Pixel8Pro/v0.2.0_Update_task.jpg
--------------------------------------------------------------------------------