Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 113 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
<<<<<<< HEAD
# Built application files
*.apk
*.aar
*.ap_
*.aab

# Files for the ART/Dalvik VM
*.dex

# Java class files
*.class

# Generated files
bin/
gen/
out/

# Gradle files
.gradle/
build/

# Local configuration file (sdk path, etc)
local.properties

# Proguard folder generated by Eclipse
proguard/

# Log Files
*.log

# Android Studio Navigation editor temp files
.navigation/

# Android Studio captures folder
captures/

# IntelliJ
*.iml
.idea/
.idea/workspace.xml
.idea/tasks.xml
.idea/gradle.xml
.idea/assetWizardSettings.xml
.idea/dictionaries
.idea/libraries
.idea/jarRepositories.xml

# Keystore files
*.jks
*.keystore

# External native build folder generated in Android Studio 2.2 and later
.externalNativeBuild
.cxx/

# Google Services (e.g. APIs or Firebase)
google-services.json

# Freeline
freeline.py
freeline/
freeline_project_description.json

# fastlane
fastlane/report.xml
fastlane/Preview.html
fastlane/screenshots
fastlane/test_output
fastlane/readme.md

# Version control
vcs.xml

# lint
lint/intermediates/
lint/generated/
lint/outputs/
lint/tmp/
lint/reports/

# Android Profiling
*.hprof
=======
# Android Studio
*.iml
.gradle/
build/
local.properties
.idea/

# Compiled files
*.class
*.dex
*.apk

# OS generated files
.DS_Store
Thumbs.db

# Logs
*.log

# Kotlin/Java
*.jar
*.war

# Other directories
node_modules/
captures/
.externalNativeBuild/
.cxx/
>>>>>>> pr-3-Santix1234-kotlinTodoApp
48 changes: 48 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
plugins {
id("com.android.application")
id("kotlin-android")
}

android {
compileSdk = 33

defaultConfig {
applicationId = "com.todoapp"
minSdk = 24
targetSdk = 33
versionCode = 1
versionName = "1.0"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}

buildTypes {
getByName("release") {
isMinifyEnabled = false
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
}
}

compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}

kotlinOptions {
jvmTarget = "11"
}
}

dependencies {
implementation("androidx.core:core-ktx:1.9.0")
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("androidx.recyclerview:recyclerview:1.3.0")

// Testing dependencies
testImplementation("junit:junit:4.13.2")
testImplementation("org.mockito:mockito-core:4.8.0")
testImplementation("org.robolectric:robolectric:4.9")

androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
}
15 changes: 15 additions & 0 deletions app/src/main/java/com/example/todoapp/data/TodoItem.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.example.todoapp.data

import androidx.room.Entity
import androidx.room.PrimaryKey

@Entity(tableName = "todo_items")
data class TodoItem(
@PrimaryKey(autoGenerate = true)
val id: Long = 0,
val title: String,
val description: String? = null,
val isCompleted: Boolean = false,
val createdAt: Long = System.currentTimeMillis(),
val updatedAt: Long = System.currentTimeMillis()
)
23 changes: 23 additions & 0 deletions app/src/main/java/com/example/todoapp/database/TodoDao.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.example.todoapp.database

import androidx.room.*
import com.example.todoapp.data.TodoItem
import kotlinx.coroutines.flow.Flow

@Dao
interface TodoDao {
@Query("SELECT * FROM todo_items")
fun getAllTodos(): Flow<List<TodoItem>>

@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertTodo(todoItem: TodoItem): Long

@Update
suspend fun updateTodo(todoItem: TodoItem)

@Delete
suspend fun deleteTodo(todoItem: TodoItem)

@Query("UPDATE todo_items SET isCompleted = :completed, updatedAt = :timestamp WHERE id = :todoId")
suspend fun updateTodoCompletionStatus(todoId: Long, completed: Boolean, timestamp: Long = System.currentTimeMillis())
}
29 changes: 29 additions & 0 deletions app/src/main/java/com/example/todoapp/database/TodoDatabase.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.example.todoapp.database

import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import com.example.todoapp.data.TodoItem

@Database(entities = [TodoItem::class], version = 1, exportSchema = false)
abstract class TodoDatabase : RoomDatabase() {
abstract fun todoDao(): TodoDao

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

fun getDatabase(context: Context): TodoDatabase {
return INSTANCE ?: synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
TodoDatabase::class.java,
"todo_database"
).build()
INSTANCE = instance
instance
}
}
}
}
19 changes: 19 additions & 0 deletions app/src/main/java/com/example/todoapp/repository/TodoRepository.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.example.todoapp.repository

import com.example.todoapp.data.TodoItem
import com.example.todoapp.database.TodoDao
import kotlinx.coroutines.flow.Flow

class TodoRepository(private val todoDao: TodoDao) {
val allTodos: Flow<List<TodoItem>> = todoDao.getAllTodos()

suspend fun insert(todoItem: TodoItem) = todoDao.insertTodo(todoItem)

suspend fun update(todoItem: TodoItem) = todoDao.updateTodo(todoItem)

suspend fun delete(todoItem: TodoItem) = todoDao.deleteTodo(todoItem)

suspend fun updateCompletionStatus(todoId: Long, isCompleted: Boolean) {
todoDao.updateTodoCompletionStatus(todoId, isCompleted)
}
}
61 changes: 61 additions & 0 deletions app/src/main/java/com/todoapp/adapter/TodoListAdapter.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package com.todoapp.adapter

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.CheckBox
import android.widget.TextView
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.todoapp.R
import com.todoapp.model.Todo

class TodoListAdapter(
private val onItemClick: (Todo) -> Unit,
private val onCompletionToggle: (Todo, Boolean) -> Unit
) : ListAdapter<Todo, TodoListAdapter.TodoViewHolder>(TodoDiffCallback()) {

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

override fun onBindViewHolder(holder: TodoViewHolder, position: Int) {
holder.bind(getItem(position))
}

class TodoViewHolder(
itemView: View,
private val onItemClick: (Todo) -> Unit,
private val onCompletionToggle: (Todo, Boolean) -> Unit
) : RecyclerView.ViewHolder(itemView) {
private val titleTextView: TextView = itemView.findViewById(R.id.todo_title)
private val completedCheckBox: CheckBox = itemView.findViewById(R.id.todo_completed_checkbox)

fun bind(todo: Todo) {
titleTextView.text = todo.title
completedCheckBox.isChecked = todo.isCompleted

itemView.setOnClickListener { onItemClick(todo) }

completedCheckBox.setOnCheckedChangeListener { _, isChecked ->
// Create a new Todo with updated completion status
val updatedTodo = todo.copy(isCompleted = isChecked)
onCompletionToggle(updatedTodo, isChecked)
}
}
}

// DiffUtil for efficient list updates
class TodoDiffCallback : DiffUtil.ItemCallback<Todo>() {
override fun areItemsTheSame(oldItem: Todo, newItem: Todo): Boolean {
return oldItem.id == newItem.id
}

override fun areContentsTheSame(oldItem: Todo, newItem: Todo): Boolean {
return oldItem == newItem
}
}
}
38 changes: 38 additions & 0 deletions app/src/main/java/com/todoapp/model/Todo.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.todoapp.model

import com.example.todoapp.data.TodoItem

data class Todo(
val id: Long = 0,
val title: String,
val description: String? = null,
val isCompleted: Boolean = false,
val createdAt: Long = System.currentTimeMillis(),
val updatedAt: Long = System.currentTimeMillis()
) {
// Conversion method to convert Todo to TodoItem
fun toTodoItem(): TodoItem {
return TodoItem(
id = id,
title = title,
description = description,
isCompleted = isCompleted,
createdAt = createdAt,
updatedAt = updatedAt
)
}

companion object {
// Conversion method to create Todo from TodoItem
fun fromTodoItem(todoItem: TodoItem): Todo {
return Todo(
id = todoItem.id,
title = todoItem.title,
description = todoItem.description,
isCompleted = todoItem.isCompleted,
createdAt = todoItem.createdAt,
updatedAt = todoItem.updatedAt
)
}
}
}
22 changes: 22 additions & 0 deletions app/src/main/res/layout/item_todo.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="16dp"
android:gravity="center_vertical">

<CheckBox
android:id="@+id/todo_completed_checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp" />

<TextView
android:id="@+id/todo_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textSize="16sp" />

</LinearLayout>
Loading