import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.unit.dp
import androidx.room.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@Entity
data class Note(
@PrimaryKey(autoGenerate = true) val id: Int = 0,
val text: String
)
@Dao
interface NoteDao {
@Insert
suspend fun insert(note: Note): Long
@Update
suspend fun update(note: Note)
@Delete
suspend fun delete(note: Note)
@Query("SELECT * FROM Note ORDER BY id DESC")
suspend fun getAll(): List<Note>
}
@Database(entities = [Note::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun noteDao(): NoteDao
}
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val db = Room.databaseBuilder(
applicationContext,
AppDatabase::class.java, "notes-db"
).build()
val noteDao = db.noteDao()
setContent {
val scope = rememberCoroutineScope()
var notes by remember { mutableStateOf(listOf<Note>()) }
var currentNoteId by remember { mutableStateOf<Int?>(null) }
var noteText by remember { mutableStateOf("") }
LaunchedEffect(Unit) {
notes = withContext(Dispatchers.IO) { noteDao.getAll() }
}
fun refreshNotes() {
scope.launch {
notes = withContext(Dispatchers.IO) { noteDao.getAll() }
}
}
Scaffold(
topBar = {
CenterAlignedTopAppBar(title = { Text("Simple Notes") })
},
content = { padding ->
Column(
modifier = Modifier
.padding(padding)
.padding(16.dp)
) {
OutlinedTextField(
value = noteText,
onValueChange = { noteText = it },
label = { Text("Enter note here") },
modifier = Modifier.fillMaxWidth()
)
Spacer(modifier = Modifier.height(8.dp))
Row {
Button(onClick = {
if (noteText.isNotBlank()) {
scope.launch {
withContext(Dispatchers.IO) {
noteDao.insert(Note(text = noteText))
}
noteText = ""
currentNoteId = null
refreshNotes()
}
}
}) {
Text("Save")
}
Spacer(modifier = Modifier.width(8.dp))
Button(onClick = {
val id = currentNoteId
if (id != null && noteText.isNotBlank()) {
scope.launch {
withContext(Dispatchers.IO) {
noteDao.update(Note(id = id, text = noteText))
}
noteText = ""
currentNoteId = null
refreshNotes()
}
}
}) {
Text("Update")
}
}
Spacer(modifier = Modifier.height(16.dp))
Text("Notes List:", style = MaterialTheme.typography.titleMedium)
Spacer(modifier = Modifier.height(8.dp))
LazyColumn {
items(notes) { note ->
Text(
text = note.text,
modifier = Modifier
.fillMaxWidth()
.clickable {
noteText = note.text
currentNoteId = note.id
}
.pointerInput(Unit) {
detectTapGestures(
onLongPress = {
scope.launch {
withContext(Dispatchers.IO) {
noteDao.delete(note)
}
if (currentNoteId == note.id) {
noteText = ""
currentNoteId = null
}
refreshNotes()
}
}
)
}
.padding(8.dp),
style = MaterialTheme.typography.bodyLarge
)
Divider()
}
}
}
}
)
}
}
}This solution uses Room to store notes with an auto-generated ID and text field.
The NoteDao interface defines suspend functions for insert, update, delete, and select all notes using Room annotations.
The Compose UI has an OutlinedTextField for entering note text, and two buttons: Save and Update.
Save inserts a new note if text is not blank. Update modifies the selected note by ID.
The notes are displayed in a scrollable list using LazyColumn. Clicking a note loads it into the text field for editing.
Long pressing a note deletes it from the database.
Coroutines run database operations off the main thread to keep UI smooth.