├── .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 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/material_theme_project_new.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/migrations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | 10 | 15 | 16 | -------------------------------------------------------------------------------- /.idea/other.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 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 | ![Menu-login](v0.2.0_Screenshot_Pixel8Pro/v0.2.0_Main_login_screen.png) 24 | 25 | ![Add-Task](v0.2.0_Screenshot_Pixel8Pro/AddTaskWImportance-Dark.jpg) 26 | 27 | ![Add-And-View](v0.2.0_Screenshot_Pixel8Pro/Importance.jpg) 28 | 29 | ![Firestore](v0.2.0_Screenshot_Pixel8Pro/Firestore.jpg) 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 |