Friday, October 15, 2021

jetpack compose - Room add remove update

MainActivity.kt

package com.example.composeroomexample

import android.app.Application
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.filled.Edit
import androidx.compose.material.icons.filled.Refresh
import androidx.compose.runtime.Composable
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import kotlinx.coroutines.launch
import java.util.*
import kotlin.random.Random

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            GetScaffold()
        }
    }
}

@Composable
fun GetScaffold(){
    val scaffoldState: ScaffoldState = rememberScaffoldState(
        snackbarHostState = SnackbarHostState()
    )
    Scaffold(
        scaffoldState = scaffoldState,
        topBar = {
            TopAppBar(
                title = { Text(text = "Compose - Room Add Remove Update")},
                backgroundColor = Color(0xFFC0E8D5),
            )
        },
        content = {MainContent(scaffoldState)},
        backgroundColor = Color(0xFFEDEAE0),
    )
}


@Composable
fun MainContent(scaffoldState: ScaffoldState){
    val scope = rememberCoroutineScope()
    val context = LocalContext.current
    val model : StudentViewModel = viewModel(
        factory = StudentViewModelFactory(
            context.applicationContext as Application)
    )
    val list:List<Student> = model.students.observeAsState(listOf()).value

    Box(
        modifier = Modifier
            .fillMaxSize()
            .padding(12.dp),
        //contentAlignment = Alignment.Center
    ){
        Column(
            verticalArrangement = Arrangement.spacedBy(12.dp)
        ) {
            Row(
                horizontalArrangement = Arrangement.spacedBy(12.dp)
            ){
                Button(onClick = {
                    model.insert(
                        Student(
                            null,
                            UUID.randomUUID().toString(),
                            Random.nextInt(10,90)
                        )
                    )
                    scope.launch{
                        scaffoldState.snackbarHostState.showSnackbar(
                            message = "Student added",
                        )
                    }
                }) {
                    Text(text = "Add Student")
                }
                Button(onClick = {
                    model.clear()
                    scope.launch{
                        scaffoldState.snackbarHostState.showSnackbar(
                            message = "All Students deleted",
                        )
                    }

                }) {
                    Text(text = "Clear")
                }
            }

            LazyColumn(
                verticalArrangement = Arrangement.spacedBy(2.dp)
            ) {
                items(list.size) { index ->
                    Card(
                        modifier = Modifier
                            .padding(2.dp)
                            .fillMaxWidth()
                            .wrapContentHeight(Alignment.CenterVertically)
                    ) {
                        Row(
                            modifier = Modifier.padding(4.dp),
                            verticalAlignment = Alignment.CenterVertically
                        ) {
                            Text(
                                text = "${list[index].id}",
                                fontWeight = FontWeight.Bold,
                                modifier = Modifier.padding(start = 12.dp)
                            )

                            Text(
                                text = " : " + list[index].fullName.take(10),
                            )

                            Text(
                                text = " : " + list[index].result,
                                style = TextStyle(
                                    color = if (list[index].result >= 33)
                                        Color(0xFF3B7A57)
                                    else Color(0xFFAB274F)),
                                modifier = Modifier.weight(2F)
                            )

                            IconButton(onClick = {
                                list[index].result = Random.nextInt(10,100)
                                model.update(list[index])
                                scope.launch{
                                    scaffoldState.snackbarHostState
                                        .showSnackbar(
                                        "Student updated id" +
                                                " : ${list[index].id}",
                                    )
                                }
                            }) {
                                Icon(Icons.Filled.Edit,"")
                            }

                            IconButton(onClick = {
                                model.delete(list[index])
                                scope.launch{
                                    scaffoldState.snackbarHostState
                                        .showSnackbar(
                                        "Student deleted id" +
                                                " : ${list[index].id}",
                                    )
                                }

                            }) {
                                Icon(Icons.Filled.Delete,"")
                            }
                        }
                    }
                }
            }
        }
    }
}
RoomSingleton.kt

package com.example.composeroomexample

import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import android.content.Context

@Database(entities = [Student::class], version = 1, exportSchema = false)
abstract class RoomSingleton : RoomDatabase() {
    abstract fun studentDao():StudentDao

    companion object {
        private var INSTANCE: RoomSingleton? = null
        fun getInstance(context: Context): RoomSingleton {
            if (INSTANCE == null) {
                INSTANCE = Room.databaseBuilder(
                    context,
                    RoomSingleton::class.java,
                    "roomdb")
                    .build()
            }
            return INSTANCE as RoomSingleton
        }
    }
}
RoomEntity.kt

package com.example.composeroomexample

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

@Entity(tableName = "studentTbl")
data class Student(
    @PrimaryKey
    var id:Long?,

    @ColumnInfo(name = "uuid")
    var fullName: String,

    @ColumnInfo(name = "result")
    var result:Int
)
RoomDao.kt

package com.example.composeroomexample

import androidx.lifecycle.LiveData
import androidx.room.*

@Dao
interface StudentDao{
    @Query("SELECT * FROM studentTbl ORDER BY id DESC")
    fun getStudents():LiveData<MutableList<Student>>

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insert(student:Student)

    @Update
    suspend fun update(student:Student)

    @Delete
    suspend fun delete(student:Student)

    @Query("DELETE FROM studentTbl")
    suspend fun clear()
}
StudentViewModel.kt

package com.example.composeroomexample

import android.app.Application
import androidx.lifecycle.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch


class StudentViewModel(application:Application)
    : AndroidViewModel(application){
    private val db:RoomSingleton = RoomSingleton
        .getInstance(application)

    internal val students : LiveData<MutableList<Student>> =
        db.studentDao().getStudents()

    fun insert(student: Student){
        viewModelScope.launch(Dispatchers.IO) {
            db.studentDao().insert(student)
        }
    }

    fun update(student: Student){
        viewModelScope.launch(Dispatchers.IO) {
            db.studentDao().update(student)
        }
    }

    fun delete(student: Student){
        viewModelScope.launch(Dispatchers.IO) {
            db.studentDao().delete(student)
        }
    }

    fun clear(){
        viewModelScope.launch(Dispatchers.IO) {
            db.studentDao().clear()
        }
    }
}


class StudentViewModelFactory(
    private val application: Application
) : ViewModelProvider.Factory {
    @Suppress("UNCHECKED_CAST")
    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
        if (modelClass.isAssignableFrom(StudentViewModel::class.java)) {
            return StudentViewModel(application) as T
        }
        throw IllegalArgumentException("Unknown ViewModel class")
    }
}
build.gradle [dependencies]

apply plugin: 'kotlin-kapt'

dependencies {
// using room database in compose
def room_version = "2.3.0"
implementation "androidx.room:room-runtime:$room_version"
implementation "androidx.room:room-ktx:$room_version"
kapt "androidx.room:room-compiler:$room_version"

implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.4.0-rc01'
implementation 'androidx.compose.runtime:runtime-livedata:1.1.0-alpha05'
}