We will be starting with a new series where I’ll create the notes app, the project is quite big so it will take around four videos to complete it.
Also, we will be covering four major advanced topics which are MVVM, Room Database, Coroutines, and Navigation Component in one single project. So, I highly recommend revising each topic before starting with the project.
Topic Videos:
Alright, let’s have a look at the demo.
This is how it looks!
I have kept the project very minimal and useful.
This will be the first screen to be displayed when there are no notes available basically in an empty notes app.
Also, there will be a floating action button which will redirect to AddNoteFragment where you can add a new note.
This is AddNoteFragment where you can add a note title and note description.
Also, there is a save button on the action bar.
This is HomeFragment, here all the notes will be displayed in a recyclerview using the staggered layout.
Also, this is the same page where empty notes were displayed but if notes are available then obviously the recyclerview will be displayed and at the top of the action bar there is a search view.
Then, this is EditNoteFragment where you can edit the note and through the floating action button, you can save the edited note.
Also, you can delete the note that is present in EditNoteFragment at the top of the action bar.
All, of these, might look very easy to you and it is indeed very easy…it’s, just that we have to write a lot of code for them.
Now, before starting with all the prerequisites…let, me quickly tell you the technical side of it, also it will be great if you guys are using the latest version of Android Studio Hedgehog 2023.1.1.
So first, there will be a blank screen if no notes are available but if there are notes available then it will display in a recycler view using a staggered layout…for, that we will require an adapter, right?
Then, notes will be saved in the room database… those, three main components are: entity, dao, and database, correct? then, they all will be handled under the repository…then, we have viewmodel for the communication…and, lastly we will have three fragments: AddNote fragment where we will add a note, EditNote fragment where we will edit the note, and HomeFragment where we will display the notes, simple right? also, the delete feature will be handled in the EditNoteFragment, and the search feature will be handled in the HomeFragment, got it?
Note: This is my practice project which works the same way as the original one but please copy only the required code because copying the entire code of gradle or manifest will lead to errors related to the project package name.
colors.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <color name="black">#FF000000</color> <color name="white">#FFFFFFFF</color> <color name="pink">#F88379</color> <color name="red">#c13b34</color> </resources>
themes.xml
<resources xmlns:tools="http://schemas.android.com/tools"> <!-- Base application theme. --> <style name="Theme.NotesRoomPractice." parent="Theme.MaterialComponents.DayNight.DarkActionBar"> <!-- Primary brand color. --> <item name="colorPrimary">@color/pink</item> <item name="colorPrimaryVariant">@color/pink</item> <item name="colorOnPrimary">@color/white</item> <!-- Secondary brand color. --> <item name="colorSecondary">@color/pink</item> <item name="colorSecondaryVariant">@color/pink</item> <item name="colorOnSecondary">@color/black</item> <!-- Status bar color. --> <item name="android:statusBarColor">?attr/colorPrimaryVariant</item> <!-- Customize your theme here. --> </style> </resources>
strings.xml
<resources> <string name="app_name">Notes</string> <!-- TODO: Remove or change this placeholder text --> <string name="hello_blank_fragment">Hello blank fragment</string> </resources>
Drawables:
pink_border.xml
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <stroke android:width="1dp" android:color="@color/pink"/> <corners android:radius="8dp"/> </shape>
Download Empty Background Image
build gradle (Project)
// Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { repositories { google() } dependencies { val navVersion = "2.7.5" classpath("androidx.navigation:navigation-safe-args-gradle-plugin:$navVersion") } } plugins { id ("com.android.application") version "7.3.1" apply false id ("com.android.library") version "7.3.1" apply false id ("org.jetbrains.kotlin.android") version "1.7.20" apply false id("com.google.devtools.ksp") version "1.9.0-1.0.13" apply false }
build gradle (Module)
plugins { id("com.android.application") id("org.jetbrains.kotlin.android") id ("kotlin-kapt") id ("kotlin-parcelize") id("com.google.devtools.ksp") id ("androidx.navigation.safeargs") } android { namespace = "com.example.notesroompractice" compileSdk = 34 defaultConfig { applicationId = "com.example.notesroompractice" minSdk = 28 targetSdk = 34 versionCode = 1 versionName = "1.0" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } buildTypes { release { isMinifyEnabled = false proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" ) } } compileOptions { sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 } kotlinOptions { jvmTarget = "1.8" } buildFeatures{ dataBinding = true } } dependencies { implementation("androidx.core:core-ktx:1.12.0") implementation("androidx.appcompat:appcompat:1.6.1") implementation("com.google.android.material:material:1.10.0") implementation("androidx.constraintlayout:constraintlayout:2.1.4") testImplementation("junit:junit:4.13.2") androidTestImplementation("androidx.test.ext:junit:1.1.5") androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1") // ROOM val roomVersion = "2.6.1" implementation ("androidx.room:room-runtime:$roomVersion") ksp("androidx.room:room-compiler:$roomVersion") // Coroutines implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1") implementation ("androidx.room:room-ktx:$roomVersion") // Navigation val navVersion = "2.7.5" implementation("androidx.navigation:navigation-fragment-ktx:$navVersion") implementation("androidx.navigation:navigation-ui-ktx:$navVersion") // Life Cycle Arch val lifecycleVersion = "2.6.2" // ViewModel implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycleVersion") // LiveData implementation("androidx.lifecycle:lifecycle-livedata-ktx:$lifecycleVersion") // Annotation processor ksp("androidx.lifecycle:lifecycle-compiler:$lifecycleVersion") }
home_menu.xml
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <item android:id="@+id/searchMenu" android:icon="@drawable/ic_search" android:title="Search" app:showAsAction="ifRoom" app:actionViewClass="androidx.appcompat.widget.SearchView" /> </menu>
menu_add_note.xml
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <item android:id="@+id/saveMenu" android:title="Save" app:showAsAction="always" /> </menu>
menu_edit_note.xml
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <item android:id="@+id/deleteMenu" android:icon="@drawable/baseline_delete_24" android:title="" app:showAsAction="always"/> </menu>
Packages and Fragments
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <application android:allowBackup="true" android:dataExtractionRules="@xml/data_extraction_rules" android:fullBackupContent="@xml/backup_rules" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.NotesRoomPractice." tools:targetApi="31"> <activity android:name=".MainActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> <meta-data android:name="android.app.lib_name" android:value=""/> </activity> <meta-data android:name="preloaded_fonts" android:resource="@array/preloaded_fonts" /> </application> </manifest>
fragment_home.xml
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto"> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".HomeFragment"> <com.google.android.material.floatingactionbutton.FloatingActionButton android:id="@+id/addNoteFab" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginEnd="20dp" android:layout_marginBottom="28dp" android:backgroundTint="@color/pink" android:clickable="true" android:contentDescription="image" android:tintMode="@color/white" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:srcCompat="@drawable/ic_add" /> <androidx.recyclerview.widget.RecyclerView android:id="@+id/homeRecyclerView" android:layout_width="match_parent" android:layout_height="match_parent" android:visibility="gone" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <ImageView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/emptyNotesImage" android:visibility="gone" android:src="@drawable/emptybkg"/> </androidx.constraintlayout.widget.ConstraintLayout> </layout>
fragment_add_note.xml
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto"> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".NewNoteFragment" android:padding="12dp"> <TextView android:id="@+id/addNoteHeading" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_marginTop="16dp" android:fontFamily="@font/poppins" android:text="Add Note." android:textStyle="bold" android:textColor="@color/red" android:textSize="24sp" /> <EditText android:id="@+id/addNoteTitle" android:layout_width="match_parent" android:layout_height="60dp" android:hint="Enter the title" android:padding="12dp" android:textSize="20sp" android:layout_below="@id/addNoteHeading" android:background="@drawable/pink_border" android:layout_marginTop="16dp" android:maxLines="1" android:fontFamily="@font/poppins"/> <EditText android:id="@+id/addNoteDesc" android:layout_width="match_parent" android:layout_height="match_parent" android:hint="Enter the description" android:gravity="top" android:padding="12dp" android:textSize="18sp" android:fontFamily="@font/poppins" android:background="@drawable/pink_border" android:layout_below="@id/addNoteTitle" android:layout_marginTop="12dp" /> </RelativeLayout> </layout>
fragment_edit_note.xml
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto"> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="12dp" tools:context=".UpdateNoteFragment"> <TextView android:id="@+id/editNoteHeading" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_marginTop="16dp" android:fontFamily="@font/poppins" android:text="Edit Note." android:textStyle="bold" android:textColor="@color/red" android:textSize="24sp" /> <EditText android:id="@+id/editNoteTitle" android:layout_width="match_parent" android:layout_height="60dp" android:hint="Enter the title" android:padding="12dp" android:textSize="20sp" android:layout_below="@id/editNoteHeading" android:background="@drawable/pink_border" android:layout_marginTop="16dp" android:maxLines="1" android:fontFamily="@font/poppins"/> <EditText android:id="@+id/editNoteDesc" android:layout_width="match_parent" android:layout_height="match_parent" android:hint="Enter the description" android:gravity="top" android:padding="12dp" android:textSize="18sp" android:fontFamily="@font/poppins" android:background="@drawable/pink_border" android:layout_below="@id/editNoteTitle" android:layout_marginTop="12dp" /> <com.google.android.material.floatingactionbutton.FloatingActionButton android:id="@+id/editNoteFab" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginEnd="20dp" android:layout_marginBottom="20dp" android:clickable="true" android:backgroundTint="@color/pink" android:tintMode="@color/white" android:src="@drawable/ic_done" android:layout_alignParentBottom="true" android:layout_alignParentEnd="true" android:contentDescription="editFab" /> </RelativeLayout> </layout>
note_layout.xml
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <androidx.cardview.widget.CardView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="8dp" app:cardElevation="6dp" app:cardCornerRadius="10dp"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:background="@drawable/pink_border" android:padding="16dp"> <TextView android:layout_width="match_parent" android:layout_height="0dp" android:id="@+id/noteTitle" android:layout_weight="200" android:textColor="@color/red" android:fontFamily="@font/poppins" android:text="Note Title" android:textStyle="bold" android:textSize="18sp"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/noteDesc" android:layout_marginTop="8dp" android:maxHeight="170dp" android:text="Description" android:textSize="14sp" android:fontFamily="@font/poppins" android:textColor="@color/pink"/> </LinearLayout> </androidx.cardview.widget.CardView> </layout>
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools"> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <androidx.fragment.app.FragmentContainerView android:id="@+id/fragmentContainerView" android:name="androidx.navigation.fragment.NavHostFragment" android:layout_width="0dp" android:layout_height="0dp" android:layout_marginStart="1dp" android:layout_marginTop="1dp" android:layout_marginEnd="1dp" android:layout_marginBottom="1dp" app:defaultNavHost="true" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:navGraph="@navigation/nav_graph" /> </androidx.constraintlayout.widget.ConstraintLayout> </layout>
nav_graph.xml
<?xml version="1.0" encoding="utf-8"?> <navigation xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/nav_graph" app:startDestination="@id/homeFragment"> <fragment android:id="@+id/homeFragment" android:name="com.example.notesroompractice.fragments.HomeFragment" android:label="fragment_home" tools:layout="@layout/fragment_home" > <action android:id="@+id/action_homeFragment_to_addNoteFragment" app:destination="@id/addNoteFragment" /> <action android:id="@+id/action_homeFragment_to_editNoteFragment" app:destination="@id/editNoteFragment" /> </fragment> <fragment android:id="@+id/addNoteFragment" android:name="com.example.notesroompractice.fragments.AddNoteFragment" android:label="fragment_add_note" tools:layout="@layout/fragment_add_note" > <action android:id="@+id/action_addNoteFragment_to_homeFragment" app:destination="@id/homeFragment" /> </fragment> <fragment android:id="@+id/editNoteFragment" android:name="com.example.notesroompractice.fragments.EditNoteFragment" android:label="fragment_edit_note" tools:layout="@layout/fragment_edit_note" > <action android:id="@+id/action_editNoteFragment_to_homeFragment" app:destination="@id/homeFragment" /> <argument android:name="note" app:argType="com.example.notesroompractice.model.Note" app:nullable="true" /> </fragment> </navigation>
All our prerequisites are done and now from the next video, the real logic begins…so, make sure you watch all the parts from the notes app playlist.
Also, for more updates you can follow us on Instagram or join our telegram group – @android_knowledge
You can create a splash screen if you want to – click here for the code
Please subscribe to my YouTube channel:
Android Knowledge – Click here