class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
val viewModel : MainViewModel = viewModel(
factory = TodoAndroidViewModelFactory(application)
)
MainScreen(viewModel = viewModel)
}
}
}
MainViewModel
//viewmodel에는 Data 조작을 위해 TodoRepository를 받도록 한다.
class MainViewModel(
application: Application,
private val todoRepository: TodoRepository
) : AndroidViewModel(application) {
private val _items = mutableStateOf(emptyList<Todo>())
val items : State<List<Todo>> = _items
//이 부분 강의에서 생략된듯?
init {
viewModelScope.launch {
todoRepository.obserbTodos()
.collect { todos ->
_items.value = todos
}
}
}
private var recentlyDeleteTodo : Todo? = null
fun addTodo(text : String){
viewModelScope.launch {
todoRepository.addTodo(Todo(title = text))
}
}
fun toggle(uid : Int) {
val todo = _items.value.find { todo -> todo.uid == uid }
todo?.let {
viewModelScope.launch {
todoRepository.updateTodo(it.copy(isDone = !it.isDone).apply {
//uid는 copy가 안되서
this.uid = it.uid
})
}
}
}
fun delete(uid : Int) {
val todo = _items.value.find{ todo -> todo.uid == uid }
todo?.let {
viewModelScope.launch {
todoRepository.deleteTodo(it)
recentlyDeleteTodo = it
}
}
}
fun restoreTodo(){
viewModelScope.launch {
//recentlyDeleteTodo가 null이면 ?:에 의하여 launch를 취소한다.
todoRepository.addTodo(recentlyDeleteTodo ?: return@launch)
recentlyDeleteTodo = null
}
}
}
class TodoAndroidViewModelFactory(
private val application: Application,
private val repository: TodoRepository = TodoRepositoryImpl(application = application),
) :
ViewModelProvider.AndroidViewModelFactory(application) {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(MainViewModel::class.java)){
return MainViewModel(application, repository) as T
}
return super.create(modelClass)
}
}
Repository
interface TodoRepository {
fun obserbTodos() : Flow<List<Todo>>
suspend fun addTodo(todo : Todo)
suspend fun updateTodo(todo : Todo)
suspend fun deleteTodo(todo : Todo)
}
class TodoRepositoryImpl(application: Application) : TodoRepository {
private val db = Room.databaseBuilder(
application,
TodoDatabase::class.java,
"todo-db",
).build()
override fun obserbTodos(): Flow<List<Todo>> {
return db.todoDao().todos()
}
override suspend fun addTodo(todo: Todo) {
return db.todoDao().insert(todo)
}
override suspend fun updateTodo(todo: Todo) {
return db.todoDao().update(todo)
}
override suspend fun deleteTodo(todo: Todo) {
return db.todoDao().delete(todo)
}
}
Room DB (DataSource & Model)
@Entity(tableName = "todo")
data class Todo(
val title : String,
val date : Long = Calendar.getInstance().timeInMillis,
val isDone : Boolean = false,
) {
@PrimaryKey(autoGenerate = true)
var uid : Int = 0
}
@Database(entities = arrayOf(Todo::class), version = 1)
abstract class TodoDatabase : RoomDatabase(){
abstract fun todoDao() : TodoDao
}
@Dao
interface TodoDao {
//flow는 비동기적인 데이터처리에 적합하다.
@Query("SELECT * FROM todo ORDER BY date DESC")
fun todos() : Flow<List<Todo>>
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(todo : Todo)
@Update
suspend fun update(todo : Todo)
@Delete
suspend fun delete(todo : Todo)
}
Todo앱
dependency
Composable TodoItem
MainActivity
MainViewModel
Repository
Room DB (DataSource & Model)