diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a30923c --- /dev/null +++ b/.gitignore @@ -0,0 +1,70 @@ +# Android Studio +<<<<<<< HEAD +.idea/ +*.iml +.gradle/ +build/ +captures/ +local.properties +.externalNativeBuild +.cxx + +# Kotlin and Java +*.class +*.kotlin_module +*.log +*.ctxt +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# Virtual Machine +.DS_Store +.mtj.tmp/ +hs_err_pid* + +# Dependency directories +/node_modules/ +kotlin-js-store/ + +# Other +.env +__pycache__/ +/out/ +======= +*.iml +.gradle/ +build/ +.idea/ +local.properties + +# Gradle files +*.gradle +**/build/ + +# Compiled class files +*.class + +# Log files +*.log + +# Virtual machine crash logs +hs_err_pid* + +# Mac system files +.DS_Store + +# Sensitive or local configuration +*.env + +# External libraries +app/libs/ + +# Test results +test-results/ +reports/ +>>>>>>> pr-4-Ralfmal-kotlinTodoApp diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..6708cf9 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,26 @@ +plugins { + id 'com.android.application' + id 'kotlin-android' + id 'kotlin-kapt' +} + +dependencies { + // Kotlin standard library + implementation "org.jetbrains.kotlin:kotlin-stdlib:1.8.0" + + // AndroidX + implementation 'androidx.core:core-ktx:1.10.1' + implementation 'androidx.appcompat:appcompat:1.6.1' + implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.1' + + // Room Database + implementation 'androidx.room:room-runtime:2.5.2' + implementation 'androidx.room:room-ktx:2.5.2' + kapt 'androidx.room:room-compiler:2.5.2' + + // Test dependencies + testImplementation 'junit:junit:4.13.2' + testImplementation 'org.robolectric:robolectric:4.10.3' + testImplementation 'androidx.test:core:1.5.0' + testImplementation 'androidx.test.ext:junit:1.1.5' +} \ No newline at end of file diff --git a/app/src/main/java/com/example/todoapp/data/TodoItem.kt b/app/src/main/java/com/example/todoapp/data/TodoItem.kt new file mode 100644 index 0000000..98cc2a7 --- /dev/null +++ b/app/src/main/java/com/example/todoapp/data/TodoItem.kt @@ -0,0 +1,18 @@ +package com.example.todoapp.data + +data class TodoItem( + val id: Long = 0, // Unique identifier, defaults to 0 for new items + val title: String, + val description: String = "", // Optional description with default empty string + val isCompleted: Boolean = false, // Default state is not completed + val createdAt: Long = System.currentTimeMillis() // Timestamp of creation +) { + /** + * Validates the todo item's core attributes + * + * @return Boolean indicating if the todo item is valid + */ + fun validate(): Boolean { + return title.trim().isNotBlank() && title.length <= 100 // Added length constraint + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/todoapp/ui/AddTodoActivity.kt b/app/src/main/java/com/example/todoapp/ui/AddTodoActivity.kt new file mode 100644 index 0000000..4871ffa --- /dev/null +++ b/app/src/main/java/com/example/todoapp/ui/AddTodoActivity.kt @@ -0,0 +1,71 @@ +package com.example.todoapp.ui + +import android.os.Bundle +import android.widget.Button +import android.widget.Toast +import androidx.appcompat.app.AppCompatActivity +import androidx.lifecycle.lifecycleScope +import com.google.android.material.textfield.TextInputEditText +import com.example.todoapp.R +import com.example.todoapp.data.TodoItem +import com.example.todoapp.data.TodoRepository +import kotlinx.coroutines.launch + +class AddTodoActivity : AppCompatActivity() { + private lateinit var titleEditText: TextInputEditText + private lateinit var descriptionEditText: TextInputEditText + private lateinit var saveButton: Button + private lateinit var todoRepository: TodoRepository + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_add_todo) + + // Initialize views + titleEditText = findViewById(R.id.titleEditText) + descriptionEditText = findViewById(R.id.descriptionEditText) + saveButton = findViewById(R.id.saveButton) + + // Initialize repository + todoRepository = TodoRepository(application) + + // Set up save button click listener + saveButton.setOnClickListener { + saveTodoItem() + } + } + + private fun saveTodoItem() { + val title = titleEditText.text.toString().trim() + val description = descriptionEditText.text.toString().trim() + + // Enhanced validation + if (title.isEmpty()) { + titleEditText.error = "Title cannot be empty" + return + } + + if (title.length > 100) { + titleEditText.error = "Title must be 100 characters or less" + return + } + + // Create TodoItem + val todoItem = TodoItem( + title = title, + description = description, + isCompleted = false + ) + + // Save asynchronously + lifecycleScope.launch { + try { + todoRepository.insert(todoItem) + Toast.makeText(this@AddTodoActivity, "Todo saved successfully!", Toast.LENGTH_SHORT).show() + finish() // Close the activity after saving + } catch (e: Exception) { + Toast.makeText(this@AddTodoActivity, "Failed to save todo: ${e.localizedMessage}", Toast.LENGTH_SHORT).show() + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/todoapp/ui/CreateTodoItemActivity.kt b/app/src/main/java/com/example/todoapp/ui/CreateTodoItemActivity.kt new file mode 100644 index 0000000..237d1bc --- /dev/null +++ b/app/src/main/java/com/example/todoapp/ui/CreateTodoItemActivity.kt @@ -0,0 +1,71 @@ +package com.example.todoapp.ui + +import android.content.Intent +import android.os.Bundle +import android.widget.Button +import android.widget.EditText +import androidx.appcompat.app.AppCompatActivity +import androidx.lifecycle.lifecycleScope +import com.example.todoapp.R +import com.example.todoapp.data.TodoItem +import com.example.todoapp.data.TodoRepository +import kotlinx.coroutines.launch + +class CreateTodoItemActivity : AppCompatActivity() { + + private lateinit var titleEditText: EditText + private lateinit var descriptionEditText: EditText + private lateinit var saveButton: Button + private lateinit var todoRepository: TodoRepository + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_create_todo_item) + + // Initialize views + titleEditText = findViewById(R.id.edit_text_todo_title) + descriptionEditText = findViewById(R.id.edit_text_todo_description) + saveButton = findViewById(R.id.button_save_todo) + + // Initialize repository (assumes dependency injection or manual initialization) + todoRepository = TodoRepository(application) + + saveButton.setOnClickListener { + saveTodoItem() + } + } + + private fun saveTodoItem() { + val title = titleEditText.text.toString().trim() + val description = descriptionEditText.text.toString().trim() + + // Basic validation + if (title.isEmpty()) { + titleEditText.error = "Title cannot be empty" + return + } + + // Create todo item + val todoItem = TodoItem( + title = title, + description = description, + isCompleted = false + ) + + // Save todo item using coroutines + lifecycleScope.launch { + todoRepository.insert(todoItem) + // Navigate back to main activity + navigateToMainActivity() + } + } + + private fun navigateToMainActivity() { + val intent = Intent(this, MainActivity::class.java) + // Clear the back stack so user can't navigate back to create todo screen + intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK + startActivity(intent) + // Finish current activity + finish() + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_add_todo.xml b/app/src/main/res/layout/activity_add_todo.xml new file mode 100644 index 0000000..db936e8 --- /dev/null +++ b/app/src/main/res/layout/activity_add_todo.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + +