タスクが追加された日付を自動的に表示する

実装するには、以下のことを行います。
- TodoItem データクラスに日付情報を追加する
TodoItem データクラスに、日付(タイムスタンプ)を保持する新しいプロパティを追加します。 - タスク追加時に日付を自動的に設定する
新しいタスクが追加される際に、現在の日付と時刻をそのプロパティに設定します。 - リスト表示時に日付を表示する
LazyColumn で各項目を表示する際に、保存された日付を整形して表示します。
具体的な手順
MainActivity.kt ファイルの TodoItem データクラスと TodoListScreen 関数を編集していきます。
1. 必要なimportを追加
ファイルの先頭あたりに、以下を追加してください。(既にあるものもあるかもしれません)
import java.text.SimpleDateFormat // 日付のフォーマット用
import java.util.Date // 日付オブジェクト用
import java.util.Locale // ロケール指定用
2. TodoItem データクラスに日付情報を追加する
TodoItem データクラスを以下のように変更します。createdAt プロパティを追加します。
// タスクのデータ構造
data class TodoItem(
val id: Long = System.currentTimeMillis(), // 一意のID
val text: String,
val category: TodoCategory,
val createdAt: Long = System.currentTimeMillis() // 追加日時(ミリ秒単位のタイムスタンプ)
)
- createdAt: Long = System.currentTimeMillis(): タスクが作成されたときのUNIXタイムスタンプ(ミリ秒)を保持します。デフォルト値として現在時刻を設定しているので、新しい TodoItem を作成する際に明示的に指定しなくても自動的に現在時刻が入ります。
3. TodoListScreen を修正して日付表示を実装する
TodoListScreen 関数の中の、LazyColumn で項目を表示している部分を修正します。TodoItem の作成ロジックは、createdAt にデフォルト値が設定されているので、特に変更する必要はありません。
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun TodoListScreen(navController: NavController) {
var todoItems by rememberSaveable { mutableStateOf(mutableListOf<TodoItem>()) }
var newTodoText by rememberSaveable(stateSaver = TextFieldValue.Saver) {
mutableStateOf(TextFieldValue(""))
}
var expanded by remember { mutableStateOf(false) }
var selectedCategory by remember { mutableStateOf(TodoCategory.NONE) }
var editingItemId by remember { mutableStateOf<Long?>(null) }
var editingText by rememberSaveable(stateSaver = TextFieldValue.Saver) {
mutableStateOf(TextFieldValue(""))
}
var editingCategory by remember { mutableStateOf(TodoCategory.NONE) }
var editingCategoryExpanded by remember { mutableStateOf(false) }
// 日付フォーマッターを定義
val dateFormatter = remember { SimpleDateFormat("yyyy/MM/dd HH:mm", Locale.JAPAN) }
Column(
modifier = Modifier.fillMaxSize().padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
// ... (省略: ToDoリストのタイトル、入力欄、カテゴリ選択、追加ボタン) ...
Text(
text = "ToDoリスト",
fontSize = 24.sp,
modifier = Modifier.padding(bottom = 16.dp)
)
OutlinedTextField(
value = newTodoText,
onValueChange = { newValue -> newTodoText = newValue },
label = { Text("新しいToDo") },
singleLine = true,
modifier = Modifier
.fillMaxWidth()
.padding(bottom = 8.dp)
)
ExposedDropdownMenuBox(
expanded = expanded,
onExpandedChange = { expanded = !expanded },
modifier = Modifier.fillMaxWidth().padding(bottom = 8.dp)
) {
OutlinedTextField(
value = selectedCategory.displayName,
onValueChange = {},
readOnly = true,
label = { Text("カテゴリを選択") },
trailingIcon = { Icon(Icons.Filled.ArrowDropDown, "ドロップダウン") },
modifier = Modifier.menuAnchor().fillMaxWidth()
)
ExposedDropdownMenu(
expanded = expanded,
onDismissRequest = { expanded = false }
) {
TodoCategory.values().forEach { category ->
DropdownMenuItem(
text = { Text(category.displayName) },
onClick = {
selectedCategory = category
expanded = false
}
)
}
}
}
Button(
onClick = {
if (newTodoText.text.isNotBlank()) {
val newTodo = TodoItem(
text = newTodoText.text,
category = selectedCategory
// createdAtはデフォルトでSystem.currentTimeMillis()が設定される
)
todoItems = (todoItems + newTodo).toMutableList()
newTodoText = TextFieldValue("")
selectedCategory = TodoCategory.NONE
}
},
modifier = Modifier.fillMaxWidth().padding(bottom = 16.dp)
) {
Text("追加")
}
// ... (省略) ...
LazyColumn(
modifier = Modifier.fillMaxSize()
) {
items(todoItems, key = { it.id }) { item ->
Card(
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 4.dp),
border = BorderStroke(1.dp, Color.LightGray)
) {
if (editingItemId == item.id) {
// 編集モードの場合 (ここは変更なし)
// ...
Row(
modifier = Modifier
.fillMaxWidth()
.background(editingCategory.color)
.padding(horizontal = 16.dp, vertical = 8.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
) {
BasicTextField(
value = editingText,
onValueChange = { editingText = it },
singleLine = true,
modifier = Modifier
.weight(1f)
.padding(end = 8.dp)
)
ExposedDropdownMenuBox(
expanded = editingCategoryExpanded,
onExpandedChange = { editingCategoryExpanded = !editingCategoryExpanded }
) {
Text(
text = editingCategory.displayName,
modifier = Modifier
.menuAnchor()
.padding(horizontal = 4.dp)
.background(Color.LightGray)
.clickable { editingCategoryExpanded = true }
)
ExposedDropdownMenu(
expanded = editingCategoryExpanded,
onDismissRequest = { editingCategoryExpanded = false }
) {
TodoCategory.values().forEach { category ->
DropdownMenuItem(
text = { Text(category.displayName) },
onClick = {
editingCategory = category
editingCategoryExpanded = false
}
)
}
}
}
IconButton(onClick = {
todoItems = todoItems.map { todo ->
if (todo.id == item.id) {
todo.copy(text = editingText.text, category = editingCategory)
} else {
todo
}
}.toMutableList()
editingItemId = null
}) {
Icon(Icons.Filled.Done, contentDescription = "編集を保存")
}
IconButton(onClick = {
editingItemId = null
}) {
Icon(Icons.Filled.Close, contentDescription = "編集をキャンセル")
}
}
} else {
// 通常表示モードの場合
Column( // RowではなくColumnを使って、日付をタスク名の下に表示
modifier = Modifier
.fillMaxWidth()
.background(item.category.color)
.padding(horizontal = 16.dp, vertical = 8.dp)
) {
Row( // タスク名と編集/削除ボタンの行
modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(
text = "[${item.category.displayName}] ${item.text}",
modifier = Modifier
.weight(1f)
.padding(end = 8.dp)
)
IconButton(onClick = {
editingItemId = item.id
editingText = TextFieldValue(item.text)
editingCategory = item.category
}) {
Icon(Icons.Filled.Edit, contentDescription = "編集")
}
IconButton(onClick = {
todoItems = todoItems.filter { it.id != item.id }.toMutableList()
}) {
Icon(Icons.Filled.Delete, contentDescription = "削除")
}
}
// ここで日付を表示
Text(
text = "追加日時: ${dateFormatter.format(Date(item.createdAt))}",
fontSize = 12.sp, // 少し小さめのフォント
color = Color.Gray, // 灰色で目立たせる
modifier = Modifier.padding(top = 4.dp)
)
}
}
}
}
}
Button(
onClick = { navController.popBackStack() },
modifier = Modifier.padding(top = 16.dp)
) {
Text("戻る")
}
}
}
- val dateFormatter = remember { SimpleDateFormat(“yyyy/MM/dd HH:mm”, Locale.JAPAN) }: 日付を「年/月/日 時:分」形式で表示するための SimpleDateFormat インスタンスを作成します。remember を使うことで、再描画時に何度も作成されないようにします。
- 通常表示モードの Row を Column で囲み、その中に元の Row(タスク名とボタン)と新しい Text(日付表示)を配置するように変更しました。これにより、タスク名の下に日付が表示されます。
- dateFormatter.format(Date(item.createdAt)): TodoItem の createdAt (Long型のタイムスタンプ) を Date オブジェクトに変換し、dateFormatter で整形して表示します。
これで、アプリを再実行すると、新しいタスクを追加した際に、タスク名のすぐ下に自動的に追加された日時が表示されるようになります!
細かい日付のフォーマット(秒まで表示するか、など)は SimpleDateFormat のパターン文字列を変更することで調整できます。
※Google AI Studioによる回答を参考にしました
