Im writing a todolist app and i want to filter the tasks based on today,past or future,im currently persisting my data via Room.
My task model:
@Parcelize
@Entity(tableName = "tasks")
data class Task(
@ColumnInfo(name = "task_title")
val title:String,
@ColumnInfo(name = "task_description")
val description:String,
@ColumnInfo(name = "task_date")
val date:LocalDateTime?,
@ColumnInfo(name = "task_category")
val category: String,
@ColumnInfo(name = "task_priority")
val priority:Int,
@IgnoredOnParcel
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "task_id")
val id:Int=0,
@ColumnInfo(name = "task_isDone")
val isDone:Boolean
):Parcelable
My Converter classes to persist the datefield into room
class DateTimeTypeConverters {
@TypeConverter
fun fromTimestamp(timestampSeconds: Long): LocalDateTime? {
return LocalDateTime.ofEpochSecond(timestampSeconds, 0, ZoneOffset.UTC)
}
@TypeConverter
fun dateToTimestamp(localDateTime: LocalDateTime?): Long {
val instant = localDateTime?.toInstant(ZoneOffset.UTC)
return instant?.toEpochMilli() ?: -1L
}
}
my viewmodel:
@HiltViewModel
class TaskViewModel @Inject constructor(private val taskRepo: TaskRepository) :ViewModel() {
val taskList: MutableLiveData<List<Task>> = taskRepo.allTasks
val foundTask: MutableLiveData<Task> = taskRepo.foundTasks
init {
taskRepo.getAllTasks()
}
fun addTask(task:Task) {
taskRepo.addTask(task)
taskRepo.getAllTasks()
}
fun deleteTask(task:Task) {
taskRepo.deleteTask(task)
taskRepo.getAllTasks()
}
fun updateTask(task:Task) {
taskRepo.updateTask(task)
taskRepo.getAllTasks()
}
fun getTaskById(id:Int) {
taskRepo.getTaskById(id)
}
fun getAllTasks() {
taskRepo.getAllTasks()
}
fun deleteAllTasks() {
taskRepo.deleteAllTasks()
taskRepo.getAllTasks()
}
}
my taskrepo:
class TaskRepository @Inject constructor(private val taskdao: TaskDao) {
val allTasks = MutableLiveData<List<Task>>()
val foundTasks = MutableLiveData<Task>()
private val coroutineScope = CoroutineScope(Dispatchers.Main)
fun addTask(task: Task){
coroutineScope.launch(Dispatchers.IO){
taskdao.addTask(task)
}
}
fun deleteTask(task: Task){
coroutineScope.launch(Dispatchers.IO){
taskdao.deleteTask(task)
}
}
fun getAllTasks() {
coroutineScope.launch(Dispatchers.IO) {
allTasks.postValue(taskdao.getAllTasks())
}
}
fun getTaskById(id: Int) {
coroutineScope.launch(Dispatchers.IO) {
foundTasks.postValue(taskdao.getTaskById(id))
}
}
fun updateTask(task: Task) {
coroutineScope.launch(Dispatchers.IO){
taskdao.updateTask(task)
}
}
fun deleteAllTasks() {
coroutineScope.launch(Dispatchers.IO) {
taskdao.deleteAllTasks()
}
}
}
My lazy column where the data needs to be displayed the dismissable class is a dummy compose func to show a swipe to dismiss card:
LazyColumn(modifier = Modifier.padding(vertical = 20.dp, horizontal = 15.dp), state = lazyListState) {
item {
Text(text =tasksList.toString(), color = Color.White)
}
when(displayByTime.value){
DisplayByTime.Today -> {
val todayItems = tasksList.filter { task->
val currentDate = LocalDate.now()
task.date?.toLocalDate()==currentDate
}
Log.i(TAG, todayItems.toString())
Log.i(TAG, LocalDate.now().toString())
Log.i(TAG,
LocalDate.now().isEqual(tasksList[0].date?.toLocalDate()).toString()
)
Log.i(TAG, LocalDate.now().isAfter(tasksList[0].date?.toLocalDate()).toString())
Log.i(TAG, LocalDate.now().isBefore(tasksList[0].date?.toLocalDate()).toString())
items(todayItems, key = {task-> task.id}){
DismissableCard()
}
}
DisplayByTime.Past->{
val pastTasks = tasksList.filter { task ->
val currentDate = LocalDate.now()
task.date?.toLocalDate()?.isBefore(currentDate) ?: false
}
Log.i(TAG, pastTasks.toString())
items(pastTasks, key = {task-> task.id}){
DismissableCard()
}
}
DisplayByTime.Future->{
val futureTasks = tasksList.filter { task ->
val currentDate = LocalDate.now()
task.date?.toLocalDate()?.isAfter(currentDate) ?: false
}
Log.i(TAG, futureTasks.toString())
items(futureTasks, key = {task-> task.id}){
DismissableCard()
}
}
}
}
Other enum classes for reference :
enum class DisplayByTime{
Past,
Today,
Future
}
enum class TaskStatus{
Completed,
Pending,
Missed,
DoneEarly
}
thee data diplayed on my emulator screen(i.e the task i persisted into the room db):
Task(title=New Task,
description=new desc + 64,
date=+56411-10-10T02:57:28,
category=University,
priority=3,
id=82,
isDone=false)
The code i used to get the above task is to persist the dummy task generated via viewmodel using the following code inside the on click function of my FAB:
Task(
title = "New Task",
description = "new desc + ${Random.nextInt(100).toString()}",
priority = 3,
date = LocalDateTime.now(),
category = "University",
isDone = false
)
the task text on the device screen is just for sake of proof that there exist some data in the main tasklist
Logs showing that the filtered list is empty:
2024-06-12 00:17:11.732 6874-6874 ContentValues com.example.todolist I []
2024-06-12 00:17:11.732 6874-6874 ContentValues com.example.todolist I 2024-06-12
2024-06-12 00:17:11.732 6874-6874 ContentValues com.example.todolist I false
2024-06-12 00:17:11.732 6874-6874 ContentValues com.example.todolist I false
2024-06-12 00:17:11.732 6874-6874 ContentValues com.example.todolist I true
I tried all that I have shown above and expect some one to debug the issue im facing.
Im expecting an answer to change the filter function inside my lazy column according to the selected ENUM
I finally solved it,
the problem is actually with my type converter classes(ill explain why but let me give you some context),
My new type converter class, thanks to betulnecanli's medium article i referred
class DateTimeTypeConverters {
// @TypeConverter [old type converter]
// fun fromTimestamp(timestampSeconds: Long): LocalDateTime? {
// return LocalDateTime.ofEpochSecond(timestampSeconds, 0,
ZoneOffset.UTC)
// }
@TypeConverter
fun fromTimestamp(value: String?): LocalDateTime? {
return value?.let { LocalDateTime.parse(it) }
}
// @TypeConverter [ old type converter]
// fun dateToTimestamp(localDateTime: LocalDateTime?): Long {
// val instant = localDateTime?.toInstant(ZoneOffset.UTC)
// return instant?.toEpochMilli() ?: -1L
// }
@TypeConverter
fun dateToTimestamp(date: LocalDateTime?): String? {
return date?.toString()
}
}
I inspected via logcat the following code:
Log.i(TAG, tasksList[0].date?.toLocalDate().toString())//Task date from db
Log.i(TAG, LocalDate.now().toString())// current db
the log values are as follows:
com.example.todolist I +56411-10-102024-06-15 17:58:32.311 5905-5905
com.example.todolist I 2024-06-15
the first log value is from my db which is not in proper format (see the second log value it should be in that format), so i changed my type converter to store it and parse it as string instead of long so i got the following result, which means it is working fine,
In short, there in nothing wrong with my filter functions, its just problem with the converters and i successfully solved it.