#75 Jetpack ComposeでToDoアプリを作る - ToDoの削除機能
本シリーズの最後にToDo削除機能を追加してみます。
ポップアップメニューを追加する
削除はボタンひとつでできるとユーザー体験的によろしくないので、ポップアップメニューの中に追加します。View
Systemの場合はapp:showAsAction
にnever
で実現できましたが、Jetpack
Composeではその部分も自作する必要があります。
@Composable
fun DetailTopBar(
navController: NavController,
todo: ToDo,
toEdit: () -> Unit,
deleteClicked: () -> Unit,
) {
var showMenu by remember { mutableStateOf(false) }
TopAppBar(
navigationIcon = {
IconButton(onClick = {
navController.popBackStack()
}) {
Icon(Icons.Filled.ArrowBack, "Back")
}
},
title = {
if (todo._id == emptyToDoId) {
Text(stringResource(id = R.string.loading))
} else {
Text(todo.title)
}
},
actions = {
if (todo._id != emptyToDoId) {
IconButton(onClick = toEdit) {
Icon(Icons.Filled.Edit, "Edit")
}
// 三点アイコン
IconButton(onClick = { showMenu = !showMenu }) {
Icon(Icons.Filled.MoreVert, "Menu")
}
// ポップアップメニュー部分
DropdownMenu(
expanded = showMenu,
onDismissRequest = { showMenu = false }
) {
DropdownMenuItem(onClick = {
// 閉じた状態に戻す
showMenu = false
deleteClicked()
}) {
Text(stringResource(id = R.string.delete_todo))
}
}
}
}
)
}
deleteClicked()
の部分は状態を変化させるだけにしています。
val showDialog = remember { mutableStateOf(false) }
DetailTopBar(navController, todo.value, {
navController.navigate("edit/${todo.value._id}")
}, { // deleteClickedの部分
showDialog.value = true
})
AlertDialogを表示する
View Systemの場合、DialogFragmentを作ったりとやや面倒でしたが、Jetpack
Composeでは表示したいタイミングでAlertDialog()
を呼ぶだけです。
@Composable
fun DetailBody(
todo: ToDo,
showDialog: MutableState<Boolean>,
performDelete: () -> Unit
) {
...
if (showDialog.value) {
AlertDialog(onDismissRequest = {
showDialog.value = false
}, title = {
Text(stringResource(id = R.string.delete_message))
}, confirmButton = {
TextButton(onClick = {
showDialog.value = false
performDelete()
}) {
Text(stringResource(id = android.R.string.ok))
}
}, dismissButton = {
TextButton(onClick = { showDialog.value = false }) {
Text(stringResource(id = android.R.string.cancel))
}
}
)
}
}
performDelete
の部分はViewModelのメソッドを呼ぶだけです。
DetailBody(todo.value, showDialog) { // performDeleteの部分
viewModel.delete(todo.value)
}
削除処理を実装する
ここからはView System版の時と同じです。
@HiltViewModel
class ToDoDetailViewModel @Inject constructor(
private val repo: ToDoRepository
) : ViewModel() {
...
val errorMessage = MutableStateFlow("")
val deleted = MutableStateFlow(false)
fun delete(todo: ToDo) {
viewModelScope.launch {
try {
repo.delete(todo)
deleted.value = true
} catch (e: Exception) {
errorMessage.value = e.message ?: ""
}
}
}
}
動作確認をする
ポップアップメニューから削除を選び、ダイアログでOKをタップすると削除されました。
ここまで作業したものはこちらにあります。