How to make a todo list app in android studio using kotlin Skip to main content

Recent Posts

Explain in detail about list and array with all function in kotlin

Explain in detail about list and array with all functions in kotlin In Kotlin, lists and arrays are fundamental collections used to store ordered sequences of elements. They provide different functionalities and usage patterns. Here is a detailed explanation of both lists and arrays in Kotlin, including their functions and usage. Lists in Kotlin A list is an ordered collection of elements. Lists can be either mutable or immutable. The main distinction is that mutable lists can be modified (elements can be added, removed, or changed), while immutable lists cannot be modified after they are created. Immutable Lists Immutable lists are created using the listOf function.    val immutableList = listOf(1, 2, 3, 4, 5) Mutable Lists Mutable lists are created using the mutableListOf function    val mutableList = mutableListOf(1, 2, 3, 4, 5) Common List Functions 1-Accessing Elements: get(index: Int): Returns the element at the specified index. first(): Returns the first elem...

How to make a todo list app in android studio using kotlin

 How to make a todo list app in Android Studio using Kotlin

Creating a simple TODO app with three activities (MainActivity, InsertActivity, UpdateActivity) and features like pinning notes, searching, and using a Room database in Android with Kotlin requires several steps. Below is a basic implementation.

 1- Setting Up the Project

  • Create a new Android project in Android Studio.

2- Add dependencies in the build. gradle:

  • Add the Room database dependencies and other necessary libraries.
       dependencies {

    // Room components
    implementation "androidx.room:room-runtime:2.4.3"
    kapt "androidx.room:room-compiler:2.4.3"
    
    // Kotlin components
    implementation "org.jetbrains.kotlin:kotlin-stdlib:1.6.10"
    
    // Lifecycle components
    implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.4.1"
    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.1"
    
    // RecyclerView
    implementation "androidx.recyclerview:recyclerview:1.2.1"
    
    // Core components
    implementation "androidx.core:core-ktx:1.7.0"
    
    // Material Design
    implementation "com.google.android.material:material:1.5.0"
}

3-Create data model for the notes:


@Entity(tableName = "notes") data class Note( @PrimaryKey(autoGenerate = true) val id: Int = 0, val title: String, val description: String, val isPinned: Boolean = false )

4- Create DAO interface:


 @Dao
interface NoteDao {
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insert(note: Note)

    @Update
    suspend fun update(note: Note)

    @Delete
    suspend fun delete(note: Note)

    @Query("SELECT * FROM notes ORDER BY isPinned DESC, id ASC")
    fun getAllNotes(): LiveData<List<Note>>
}

5- Create Room Database

    @Database(entities = [Note::class], version = 1, exportSchema = false)
abstract class NoteDatabase : RoomDatabase() {
    abstract fun noteDao(): NoteDao

    companion object {
        @Volatile
        private var INSTANCE: NoteDatabase? = null

        fun getDatabase(context: Context): NoteDatabase {
            return INSTANCE ?: synchronized(this) {
                val instance = Room.databaseBuilder(
                    context.applicationContext,
                    NoteDatabase::class.java,
                    "note_database"
                ).build()
                INSTANCE = instance
                instance
            }
        }
    }
}

6- Create Repository Class

    class NoteRepository(private val noteDao: NoteDao) {
    val allNotes: LiveData<List<Note>> = noteDao.getAllNotes()

    suspend fun insert(note: Note) {
        noteDao.insert(note)
    }

    suspend fun update(note: Note) {
        noteDao.update(note)
    }

    suspend fun delete(note: Note) {
        noteDao.delete(note)
    }
}

7 - Create View Model 

    class NoteViewModel(application: Application) : AndroidViewModel(application) {
    private val repository: NoteRepository
    val allNotes: LiveData<List<Note>>

    init {
        val noteDao = NoteDatabase.getDatabase(application).noteDao()
        repository = NoteRepository(noteDao)
        allNotes = repository.allNotes
    }

    fun insert(note: Note) = viewModelScope.launch {
        repository.insert(note)
    }

    fun update(note: Note) = viewModelScope.launch {
        repository.update(note)
    }

    fun delete(note: Note) = viewModelScope.launch {
        repository.delete(note)
    }
}

8- Create an Adapter Class Using Kotlin

      class NoteAdapter(private val listener: OnItemClickListener) : RecyclerView.Adapter<NoteAdapter.NoteViewHolder>() {
    private var notes: List<Note> = emptyList()

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NoteViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.item_note, parent, false)
        return NoteViewHolder(view)
    }

    override fun onBindViewHolder(holder: NoteViewHolder, position: Int) {
        val note = notes[position]
        holder.bind(note)
    }

    override fun getItemCount(): Int {
        return notes.size
    }

    fun setNotes(notes: List<Note>) {
        this.notes = notes
        notifyDataSetChanged()
    }

    inner class NoteViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), View.OnClickListener {
        private val titleTextView: TextView = itemView.findViewById(R.id.titleTextView)
        private val descriptionTextView: TextView = itemView.findViewById(R.id.descriptionTextView)
        private val pinImageView: ImageView = itemView.findViewById(R.id.pinImageView)

        init {
            itemView.setOnClickListener(this)
            pinImageView.setOnClickListener {
                listener.onPinClick(notes[adapterPosition])
            }
        }

        fun bind(note: Note) {
            titleTextView.text = note.title
            descriptionTextView.text = note.description
            pinImageView.setImageResource(if (note.isPinned) R.drawable.ic_pinned else R.drawable.ic_unpinned)
        }

        override fun onClick(v: View?) {
            listener.onItemClick(notes[adapterPosition])
        }
    }

    interface OnItemClickListener {
        fun onItemClick(note: Note)
        fun onPinClick(note: Note)
    }
}

9 Create Layout -:

  • create_main_activty.xml
           <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <EditText
        android:id="@+id/searchEditText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Search notes"
        android:padding="16dp" />

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@id/searchEditText"
        android:padding="16dp" />
    
    <Button
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentEnd="true"
        android:layout_margin="16dp"
        android:background="?attr/colorPrimary"
        android:text="Add" />
</RelativeLayout>
  • item_notes.xml
         <?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginBottom="8dp"
    app:cardCornerRadius="8dp">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="16dp">

        <TextView
            android:id="@+id/titleTextView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textStyle="bold"
            android:textSize="16sp" />

        <TextView
            android:id="@+id/descriptionTextView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/titleTextView"
            android:textSize="14sp" />

        <ImageView
            android:id="@+id/pinImageView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentEnd="true"
            android:layout_centerVertical="true"
            android:src="@drawable/ic_unpinned" />
    </RelativeLayout>
</androidx.cardview.widget.CardView>
       
  •      activity_insert.xml and activity_update.xml
           These layouts will be similar and include EditTexts for title and description and a Button to save the note.

<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".InsertActivity"> <EditText android:id="@+id/titleEditText" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Title" android:padding="16dp" /> <EditText android:id="@+id/descriptionEditText" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/titleEditText" android:hint="Description" android:padding="16dp" /> <Button android:id="@+id/saveButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/descriptionEditText" android:layout_centerHorizontal="true" android:layout_marginTop="16dp" android:text="Save" /> </RelativeLayout>

10- Implement Activities 

  • Main Activity
         class MainActivity : AppCompatActivity(), NoteAdapter.OnItemClickListener {
    private lateinit var noteViewModel: NoteViewModel
    private lateinit var adapter: NoteAdapter

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        adapter = NoteAdapter(this)
        val recyclerView: RecyclerView = findViewById(R.id.recyclerView)
        recyclerView.adapter = adapter
        recyclerView.layoutManager = LinearLayoutManager(this)

        noteViewModel = ViewModelProvider(this).get(NoteViewModel::class.java)
        noteViewModel.allNotes.observe(this, Observer { notes ->
            notes?.let { adapter.setNotes(it) }
        })

        val searchEditText: EditText = findViewById(R.id.searchEditText)
        searchEditText.addTextChangedListener(object : TextWatcher {
            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
                val query = s.toString().trim()
                adapter.setNotes(noteViewModel.allNotes.value?.filter {
                    it.title.contains(query, ignoreCase = true) || it.description.contains(query, ignoreCase = true)
                } ?: emptyList())
            }
            override fun afterTextChanged(s: Editable?) {}
        })

        findViewById<Button>(R.id.fab).setOnClickListener {
            startActivity(Intent(this, InsertActivity::class.java))
        }
    }

    override fun onItemClick(note: Note) {
        val intent = Intent(this, UpdateActivity::class.java)
        intent.putExtra("note_id", note.id)
        startActivity(intent)
    }

    override fun onPinClick(note: Note) {
        noteViewModel.update(note.copy(isPinned = !note.isPinned))
    }
}
  • Insert Activity
      class InsertActivity : AppCompatActivity() {
    private lateinit var noteViewModel: NoteViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_insert)

        noteViewModel = ViewModelProvider(this).get(NoteViewModel::class.java)

        findViewById<Button>(R.id.saveButton).setOnClickListener {
            val title = findViewById<EditText>(R.id.titleEditText).text.toString()
            val description = findViewById<EditText>(R.id.descriptionEditText).text.toString()

            if (title.isNotEmpty() && description.isNotEmpty()) {
                noteViewModel.insert(Note(title = title, description = description))
                finish()
            } else {
                Toast.makeText(this, "Please enter both title and description", Toast.LENGTH_SHORT).show()
            }
        }
    }
}
  • Update Activity
        class UpdateActivity : AppCompatActivity() {
    private lateinit var noteViewModel: NoteViewModel
    private var noteId: Int = -1

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_update)

        noteViewModel = ViewModelProvider(this).get(NoteViewModel::class.java)
        noteId = intent.getIntExtra("note_id", -1)

        val titleEditText: EditText = findViewById(R.id.titleEditText)
        val descriptionEditText: EditText = findViewById(R.id.descriptionEditText)

        if (noteId != -1) {
            noteViewModel.allNotes.observe(this, Observer { notes ->
                val note = notes.find { it.id == noteId }
                note?.let {
                    titleEditText.setText(it.title)
                    descriptionEditText.setText(it.description)
                }
            })
        }

        findViewById<Button>(R.id.saveButton).setOnClickListener {
            val title = titleEditText.text.toString()
            val description = descriptionEditText.text.toString()

            if (title.isNotEmpty() && description.isNotEmpty()) {
                noteViewModel.update(Note(id = noteId, title = title, description = description))
                finish()
            } else {
                Toast.makeText(this, "Please enter both title and description", Toast.LENGTH_SHORT).show()
            }
        }
    }
}

This setup should give you a basic TODO app with pinning, searching, inserting, updating, and deleting notes using Room, ViewModel, LiveData, and RecyclerView in Kotlin. Adjust the code and add more features as needed.


Comments