Skip to content
Open
106 changes: 106 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<<<<<<< HEAD
# Gradle files
.gradle/
build/

# Local configuration file
local.properties

# Android Studio generated files
*.iml
.idea/
=======
# Android Studio
*.iml
.gradle
/local.properties
/.idea/workspace.xml
/.idea/libraries
.DS_Store
/build
/captures
.externalNativeBuild

# Gradle files
gradle-app.setting
!gradle-wrapper.jar
.gradletasknamecache
>>>>>>> pr-7-Ralfmal-kotlinTodoApp

# Compiled class files
*.class

# Log files
*.log

<<<<<<< HEAD
# Android generated files
bin/
gen/
out/

# Dependency directories
/captures
.externalNativeBuild
.cxx

# macOS system files
.DS_Store

# Backup files
*.bak
*.swp

# Kotlin build artifacts
*.jar
*.war
*.ear
=======
# Package Files
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
>>>>>>> pr-7-Ralfmal-kotlinTodoApp

# Virtual machine crash logs
hs_err_pid*

<<<<<<< HEAD
# Android Profiling
*.hprof
=======
# Android specific
bin/
gen/
out/
release/

# Android Profiling
*.hprof

# Dependency directories
/node_modules
/jspm_packages

# Editor directories and files
.idea/
.vscode/
*.swp
*.swo

# Environment files
.env

# Secrets
*.key
secrets.json

# Build output
/build
/dist
/target
>>>>>>> pr-7-Ralfmal-kotlinTodoApp
82 changes: 82 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
plugins {
id("com.android.application")
<<<<<<< HEAD
id("org.jetbrains.kotlin.android")
=======
id("kotlin-android")
>>>>>>> pr-7-Ralfmal-kotlinTodoApp
id("kotlin-kapt")
}

android {
<<<<<<< HEAD
namespace = "com.todoapp"
compileSdk = 33

defaultConfig {
applicationId = "com.todoapp"
=======
compileSdk = 33
defaultConfig {
applicationId = "com.example.todoapp"
>>>>>>> pr-7-Ralfmal-kotlinTodoApp
minSdk = 24
targetSdk = 33
versionCode = 1
versionName = "1.0"
<<<<<<< HEAD

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"
}
}

dependencies {
// Room Database
implementation("androidx.room:room-runtime:2.5.1")
implementation("androidx.room:room-ktx:2.5.1")
kapt("androidx.room:room-compiler:2.5.1")

// Kotlin standard library
implementation("org.jetbrains.kotlin:kotlin-stdlib:1.8.20")

// Testing
testImplementation("junit:junit:4.13.2")
testImplementation("org.jetbrains.kotlin:kotlin-test:1.8.20")

// Android testing
=======
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
}

dependencies {
// Room dependencies
val roomVersion = "2.5.1"
implementation("androidx.room:room-runtime:$roomVersion")
implementation("androidx.room:room-ktx:$roomVersion")
kapt("androidx.room:room-compiler:$roomVersion")

// Testing dependencies
testImplementation("androidx.room:room-testing:$roomVersion")
testImplementation("junit:junit:4.13.2")
>>>>>>> pr-7-Ralfmal-kotlinTodoApp
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
}
80 changes: 80 additions & 0 deletions app/src/main/java/com/example/todoapp/data/dao/TodoItemDao.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package com.example.todoapp.data.dao

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

@Dao
interface TodoItemDao {
/**
* Inserts a new todo item into the database.
* @param todoItem The todo item to insert
* @return The ID of the newly inserted item
*/
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(todoItem: TodoItem): Long

/**
* Inserts multiple todo items into the database.
* @param todoItems The list of todo items to insert
* @return List of inserted item IDs
*/
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertAll(todoItems: List<TodoItem>): List<Long>

/**
* Updates an existing todo item.
* @param todoItem The todo item with updated information
*/
@Update
suspend fun update(todoItem: TodoItem)

/**
* Deletes a specific todo item.
* @param todoItem The todo item to delete
*/
@Delete
suspend fun delete(todoItem: TodoItem)

/**
* Retrieves a todo item by its ID.
* @param id The ID of the todo item
* @return The todo item or null if not found
*/
@Query("SELECT * FROM todo_items WHERE id = :id")
suspend fun getById(id: Long): TodoItem?

/**
* Retrieves all todo items, sorted by creation date.
* @return A Flow of todo items
*/
@Query("SELECT * FROM todo_items ORDER BY createdAt DESC")
fun getAllTodoItems(): Flow<List<TodoItem>>

/**
* Retrieves completed todo items.
* @return A Flow of completed todo items
*/
@Query("SELECT * FROM todo_items WHERE isCompleted = 1 ORDER BY updatedAt DESC")
fun getCompletedTodoItems(): Flow<List<TodoItem>>

/**
* Retrieves active (not completed) todo items.
* @return A Flow of active todo items
*/
@Query("SELECT * FROM todo_items WHERE isCompleted = 0 ORDER BY createdAt DESC")
fun getActiveTodoItems(): Flow<List<TodoItem>>

/**
* Deletes all todo items from the database.
*/
@Query("DELETE FROM todo_items")
suspend fun deleteAll()

/**
* Counts the total number of todo items.
* @return The total number of todo items
*/
@Query("SELECT COUNT(*) FROM todo_items")
suspend fun count(): Int
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.example.todoapp.data.database

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

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

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
}
}
}
}
15 changes: 15 additions & 0 deletions app/src/main/java/com/example/todoapp/data/model/TodoItem.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.example.todoapp.data.model

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()
)
38 changes: 38 additions & 0 deletions app/src/main/java/com/todoapp/data/entity/Todo.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// DEPRECATED: Replaced by TodoItem in com.example.todoapp.data.model
// This file is kept for historical reference and will be removed in future refactoring
package com.todoapp.data.entity

import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import java.time.LocalDateTime

/**
* @deprecated Use TodoItem from com.example.todoapp.data.model instead
*/
@Deprecated("Use TodoItem from com.example.todoapp.data.model package")
@Entity(tableName = "todos")
data class Todo(
@PrimaryKey(autoGenerate = true)
val id: Int = 0,

@ColumnInfo(name = "title")
val title: String,

@ColumnInfo(name = "description")
val description: String? = null,

@ColumnInfo(name = "is_completed")
val isCompleted: Boolean = false,

@ColumnInfo(name = "created_at")
val createdAt: LocalDateTime = LocalDateTime.now(),

@ColumnInfo(name = "due_date")
val dueDate: LocalDateTime? = null
) {
init {
require(title.isNotBlank()) { "Title cannot be blank" }
require(title.length <= 100) { "Title cannot exceed 100 characters" }
description?.let {
require(it.length <= 500) { "Description cannot exceed 500 characters\" }\n }\n }\n}
Loading