Android Knowledge

The Notes App – Prerequisites & XML Design

notes app

Project Overview

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:

  1. MVVM:
    https://youtu.be/DTE1dbdluh4
  2. ROOM:
    https://youtu.be/zWbryaoVBuk
  3. Navigation Component:
    https://youtu.be/yWWuOqFRwfg
  4. Coroutines:
    https://youtu.be/onnnefZCgmQ

Project Demo

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.

add 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.

Technical Talks about Project

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?

Source Code

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:

  1. Search for the delete, add, done, and search icons and add them.
  2. Create a pink_border.
  3. Add an empty background image.

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>

Fragments XML Layouts

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>

Conclusion

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