Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.escodro.local.dao

import com.escodro.local.ChecklistItem
import kotlinx.coroutines.flow.Flow

/**
* Data Access Object to access Checklist data.
*/
interface ChecklistDao {

/**
* Inserts a new checklist item.
*
* @param item checklist item to be added
*/
suspend fun insertChecklistItem(item: ChecklistItem)

/**
* Updates a checklist item.
*
* @param item checklist item to be updated
*/
suspend fun updateChecklistItem(item: ChecklistItem)

/**
* Deletes a checklist item.
*
* @param item checklist item to be deleted
*/
suspend fun deleteChecklistItem(item: ChecklistItem)

/**
* Gets the checklist items from a task.
*
* @param taskId the task id
*
* @return the checklist items from the task
*/
fun getChecklistItems(taskId: Long): Flow<List<ChecklistItem>>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.escodro.local.dao.impl

import app.cash.sqldelight.coroutines.asFlow
import app.cash.sqldelight.coroutines.mapToList
import com.escodro.coroutines.CoroutineDispatcherProvider
import com.escodro.local.ChecklistItem
import com.escodro.local.ChecklistItemQueries
import com.escodro.local.dao.ChecklistDao
import com.escodro.local.provider.DatabaseProvider
import kotlinx.coroutines.flow.Flow

internal class ChecklistDaoImpl(
private val databaseProvider: DatabaseProvider,
private val dispatcherProvider: CoroutineDispatcherProvider,
) : ChecklistDao {

private val checklistItemQueries: ChecklistItemQueries
get() = databaseProvider.getInstance().checklistItemQueries

override suspend fun insertChecklistItem(item: ChecklistItem) {
checklistItemQueries.insertItem(
item_task_id = item.item_task_id,
item_title = item.item_title,
item_is_completed = item.item_is_completed,
)
}

override suspend fun updateChecklistItem(item: ChecklistItem) {
checklistItemQueries.updateItem(
item_title = item.item_title,
item_is_completed = item.item_is_completed,
item_id = item.item_id,
)
}

override suspend fun deleteChecklistItem(item: ChecklistItem) {
checklistItemQueries.deleteItem(item.item_id)
}

override fun getChecklistItems(taskId: Long): Flow<List<ChecklistItem>> =
checklistItemQueries.selectByTaskId(taskId)
.asFlow()
.mapToList(dispatcherProvider.io)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.escodro.local.datasource

import com.escodro.local.dao.ChecklistDao
import com.escodro.local.mapper.ChecklistItemMapper
import com.escodro.repository.datasource.ChecklistDataSource
import com.escodro.repository.model.ChecklistItem
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map

internal class ChecklistLocalDataSource(
private val checklistDao: ChecklistDao,
private val checklistMapper: ChecklistItemMapper,
) : ChecklistDataSource {

override suspend fun insertChecklistItem(item: ChecklistItem) =
checklistDao.insertChecklistItem(checklistMapper.toLocal(item))

override suspend fun updateChecklistItem(item: ChecklistItem) {
checklistDao.updateChecklistItem(checklistMapper.toLocal(item))
}

override suspend fun deleteChecklistItem(item: ChecklistItem) {
checklistDao.deleteChecklistItem(checklistMapper.toLocal(item))
}

override fun getChecklistItems(taskId: Long): Flow<List<ChecklistItem>> =
checklistDao.getChecklistItems(taskId).map { list ->
list.map { checklistMapper.toRepo(it) }
}
}
Original file line number Diff line number Diff line change
@@ -1,22 +1,27 @@
package com.escodro.local.di

import com.escodro.local.dao.CategoryDao
import com.escodro.local.dao.ChecklistDao
import com.escodro.local.dao.TaskDao
import com.escodro.local.dao.TaskWithCategoryDao
import com.escodro.local.dao.impl.CategoryDaoImpl
import com.escodro.local.dao.impl.ChecklistDaoImpl
import com.escodro.local.dao.impl.TaskDaoImpl
import com.escodro.local.dao.impl.TaskWithCategoryDaoImpl
import com.escodro.local.datasource.CategoryLocalDataSource
import com.escodro.local.datasource.ChecklistLocalDataSource
import com.escodro.local.datasource.SearchLocalDataSource
import com.escodro.local.datasource.TaskLocalDataSource
import com.escodro.local.datasource.TaskWithCategoryLocalDataSource
import com.escodro.local.mapper.AlarmIntervalMapper
import com.escodro.local.mapper.CategoryMapper
import com.escodro.local.mapper.ChecklistItemMapper
import com.escodro.local.mapper.SelectMapper
import com.escodro.local.mapper.TaskMapper
import com.escodro.local.mapper.TaskWithCategoryMapper
import com.escodro.local.provider.DatabaseProvider
import com.escodro.repository.datasource.CategoryDataSource
import com.escodro.repository.datasource.ChecklistDataSource
import com.escodro.repository.datasource.SearchDataSource
import com.escodro.repository.datasource.TaskDataSource
import com.escodro.repository.datasource.TaskWithCategoryDataSource
Expand All @@ -36,17 +41,20 @@ val localModule = module {
singleOf(::CategoryLocalDataSource) bind CategoryDataSource::class
singleOf(::TaskWithCategoryLocalDataSource) bind TaskWithCategoryDataSource::class
singleOf(::SearchLocalDataSource) bind SearchDataSource::class
singleOf(::ChecklistLocalDataSource) bind ChecklistDataSource::class

// Mappers
factoryOf(::AlarmIntervalMapper)
factoryOf(::TaskMapper)
factoryOf(::CategoryMapper)
factoryOf(::TaskWithCategoryMapper)
factoryOf(::SelectMapper)
factoryOf(::ChecklistItemMapper)

// DAOs
singleOf(::CategoryDaoImpl) bind CategoryDao::class
singleOf(::TaskDaoImpl) bind TaskDao::class
singleOf(::ChecklistDaoImpl) bind ChecklistDao::class
singleOf(::TaskWithCategoryDaoImpl) bind TaskWithCategoryDao::class

// Providers
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.escodro.local.mapper

import com.escodro.local.ChecklistItem as LocalChecklistItem
import com.escodro.repository.model.ChecklistItem as RepoChecklistItem

internal class ChecklistItemMapper {

fun toRepo(local: LocalChecklistItem): RepoChecklistItem =
RepoChecklistItem(
id = local.item_id,
taskId = local.item_task_id,
title = local.item_title,
isCompleted = local.item_is_completed,
)

fun toLocal(repo: RepoChecklistItem): LocalChecklistItem =
LocalChecklistItem(
item_id = repo.id,
item_task_id = repo.taskId,
item_title = repo.title,
item_is_completed = repo.isCompleted,
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import kotlin.Boolean;

CREATE TABLE IF NOT EXISTS ChecklistItem (
item_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
item_task_id INTEGER NOT NULL,
item_title TEXT NOT NULL,
item_is_completed INTEGER AS Boolean NOT NULL DEFAULT 0,
FOREIGN KEY(item_task_id) REFERENCES Task(task_id) ON UPDATE NO ACTION ON DELETE CASCADE
);

CREATE INDEX IF NOT EXISTS index_ChecklistItem_item_task_id ON ChecklistItem (item_task_id);

insertItem:
INSERT INTO ChecklistItem(item_task_id, item_title, item_is_completed)
VALUES (?, ?, ?);

updateItem:
UPDATE ChecklistItem
SET item_title = ?,
item_is_completed = ?
WHERE item_id = ?;

deleteItem:
DELETE FROM ChecklistItem
WHERE item_id = ?;

selectByTaskId:
SELECT *
FROM ChecklistItem
WHERE item_task_id = ?;
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.escodro.repository

import com.escodro.domain.model.ChecklistItem
import com.escodro.domain.repository.ChecklistRepository
import com.escodro.repository.datasource.ChecklistDataSource
import com.escodro.repository.mapper.ChecklistItemMapper
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map

internal class ChecklistRepositoryImpl(
private val checklistDataSource: ChecklistDataSource,
private val checklistMapper: ChecklistItemMapper,
) : ChecklistRepository {

override suspend fun insertChecklistItem(item: ChecklistItem) {
checklistDataSource.insertChecklistItem(checklistMapper.toRepo(item))
}

override suspend fun updateChecklistItem(item: ChecklistItem) {
checklistDataSource.updateChecklistItem(checklistMapper.toRepo(item))
}

override suspend fun deleteChecklistItem(item: ChecklistItem) {
checklistDataSource.deleteChecklistItem(checklistMapper.toRepo(item))
}

override fun getChecklistItems(taskId: Long): Flow<List<ChecklistItem>> {
return checklistDataSource.getChecklistItems(taskId).map { list ->
list.map { checklistMapper.toDomain(it) }
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.escodro.repository.datasource

import com.escodro.repository.model.ChecklistItem
import kotlinx.coroutines.flow.Flow

interface ChecklistDataSource {
suspend fun insertChecklistItem(item: ChecklistItem)
suspend fun updateChecklistItem(item: ChecklistItem)
suspend fun deleteChecklistItem(item: ChecklistItem)
fun getChecklistItems(taskId: Long): Flow<List<ChecklistItem>>
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import com.escodro.domain.repository.CategoryRepository
import com.escodro.domain.repository.SearchRepository
import com.escodro.domain.repository.TaskRepository
import com.escodro.domain.repository.TaskWithCategoryRepository
import com.escodro.domain.repository.ChecklistRepository
import com.escodro.repository.ChecklistRepositoryImpl
import com.escodro.domain.usecase.preferences.PreferencesRepository
import com.escodro.repository.CategoryRepositoryImpl
import com.escodro.repository.PreferencesRepositoryImpl
Expand All @@ -13,6 +15,7 @@ import com.escodro.repository.TaskWithCategoryRepositoryImpl
import com.escodro.repository.mapper.AlarmIntervalMapper
import com.escodro.repository.mapper.AppThemeOptionsMapper
import com.escodro.repository.mapper.CategoryMapper
import com.escodro.repository.mapper.ChecklistItemMapper
import com.escodro.repository.mapper.TaskMapper
import com.escodro.repository.mapper.TaskWithCategoryMapper
import org.koin.core.module.dsl.factoryOf
Expand All @@ -28,13 +31,15 @@ val repositoryModule = module {
// Repositories
singleOf(::TaskRepositoryImpl) bind TaskRepository::class
singleOf(::CategoryRepositoryImpl) bind CategoryRepository::class
singleOf(::ChecklistRepositoryImpl) bind ChecklistRepository::class
singleOf(::TaskWithCategoryRepositoryImpl) bind TaskWithCategoryRepository::class
singleOf(::SearchRepositoryImpl) bind SearchRepository::class
singleOf(::PreferencesRepositoryImpl) bind PreferencesRepository::class

// Mappers
factoryOf(::AlarmIntervalMapper)
factoryOf(::TaskMapper)
factoryOf(::ChecklistItemMapper)
factoryOf(::CategoryMapper)
factoryOf(::TaskWithCategoryMapper)
factoryOf(::AppThemeOptionsMapper)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.escodro.repository.mapper

import com.escodro.domain.model.ChecklistItem as DomainChecklistItem
import com.escodro.repository.model.ChecklistItem as RepoChecklistItem

internal class ChecklistItemMapper {

fun toRepo(domain: DomainChecklistItem): RepoChecklistItem =
RepoChecklistItem(
id = domain.id,
taskId = domain.taskId,
title = domain.title,
isCompleted = domain.isCompleted,
)

fun toDomain(repo: RepoChecklistItem): DomainChecklistItem =
DomainChecklistItem(
id = repo.id,
taskId = repo.taskId,
title = repo.title,
isCompleted = repo.isCompleted,
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.escodro.repository.model

/**
* Data class to represent a Checklist Item.
*
* @property id unique checklist item id
* @property taskId the associated task id
* @property title the checklist item title
* @property isCompleted indicates if the checklist item is completed
*/
data class ChecklistItem(
val id: Long = 0,
val taskId: Long,
val title: String,
val isCompleted: Boolean = false,
)
10 changes: 10 additions & 0 deletions domain/src/commonMain/kotlin/com/escodro/domain/di/DomainModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ import com.escodro.domain.usecase.task.UpdateTaskCategory
import com.escodro.domain.usecase.task.UpdateTaskDescription
import com.escodro.domain.usecase.task.UpdateTaskStatus
import com.escodro.domain.usecase.task.UpdateTaskTitle
import com.escodro.domain.usecase.checklist.AddChecklistItem
import com.escodro.domain.usecase.checklist.DeleteChecklistItem
import com.escodro.domain.usecase.checklist.LoadChecklistItems
import com.escodro.domain.usecase.checklist.UpdateChecklistItem
import com.escodro.domain.usecase.task.implementation.AddTaskImpl
import com.escodro.domain.usecase.task.implementation.LoadTaskImpl
import com.escodro.domain.usecase.task.implementation.UpdateTaskCategoryImpl
Expand Down Expand Up @@ -122,6 +126,12 @@ val domainModule = module {
factoryOf(::UpdateAppTheme)
factoryOf(::LoadAppTheme)

// Checklist Use Cases
factoryOf(::AddChecklistItem)
factoryOf(::DeleteChecklistItem)
factoryOf(::LoadChecklistItems)
factoryOf(::UpdateChecklistItem)

// Providers
factoryOf(::DateTimeProviderImpl) bind DateTimeProvider::class
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.escodro.domain.model

/**
* Data class to represent a Checklist Item.
*
* @property id unique checklist item id
* @property taskId the associated task id
* @property title the checklist item title
* @property isCompleted indicates if the checklist item is completed
*/
data class ChecklistItem(
val id: Long = 0,
val taskId: Long,
val title: String,
val isCompleted: Boolean = false,
)
Loading