From 1b86870add845f908446c17bfaf9c5197ae2874d Mon Sep 17 00:00:00 2001 From: lyzlovazlata Date: Sat, 11 Apr 2026 10:34:40 +0300 Subject: [PATCH 1/5] Change time and id asignment logic (only tests, usecase) --- ai/build.gradle.kts | 2 +- app/build.gradle.kts | 2 +- data/build.gradle.kts | 2 +- domain/build.gradle.kts | 2 +- .../domain/usecase/CreateFolderUseCase.kt | 10 +++++-- .../itlab/domain/usecase/CreateNoteUseCase.kt | 10 ++++++- .../com/itlab/domain/FolderUseCasesTest.kt | 28 +++++++++++-------- .../java/com/itlab/domain/NoteUseCasesTest.kt | 26 +++++++++-------- 8 files changed, 51 insertions(+), 31 deletions(-) diff --git a/ai/build.gradle.kts b/ai/build.gradle.kts index 2218887..67d1eee 100644 --- a/ai/build.gradle.kts +++ b/ai/build.gradle.kts @@ -7,7 +7,7 @@ plugins { android { namespace = "com.itlab.ai" compileSdk { - version = release(37) + version = preview("CinnamonBun") } defaultConfig { diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 1bbae64..782cb25 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -8,7 +8,7 @@ plugins { android { namespace = "com.itlab.notes" compileSdk { - version = release(37) + version = preview("CinnamonBun") } defaultConfig { diff --git a/data/build.gradle.kts b/data/build.gradle.kts index d7aab12..979654b 100644 --- a/data/build.gradle.kts +++ b/data/build.gradle.kts @@ -8,7 +8,7 @@ plugins { android { namespace = "com.itlab.data" - compileSdk = 37 + compileSdkPreview = "CinnamonBun" defaultConfig { minSdk = 33 diff --git a/domain/build.gradle.kts b/domain/build.gradle.kts index f9bed20..b74a693 100644 --- a/domain/build.gradle.kts +++ b/domain/build.gradle.kts @@ -8,7 +8,7 @@ plugins { android { namespace = "com.itlab.domain" compileSdk { - version = release(37) + version = preview("CinnamonBun") } defaultConfig { diff --git a/domain/src/main/java/com/itlab/domain/usecase/CreateFolderUseCase.kt b/domain/src/main/java/com/itlab/domain/usecase/CreateFolderUseCase.kt index b0d06dc..e4d68a7 100644 --- a/domain/src/main/java/com/itlab/domain/usecase/CreateFolderUseCase.kt +++ b/domain/src/main/java/com/itlab/domain/usecase/CreateFolderUseCase.kt @@ -3,13 +3,19 @@ package com.itlab.domain.usecase import com.itlab.domain.model.NoteFolder import com.itlab.domain.repository.NoteFolderRepository import kotlinx.datetime.Clock +import java.util.UUID class CreateFolderUseCase( private val repo: NoteFolderRepository, ) { suspend operator fun invoke(folder: NoteFolder): String { - // discuss - val folder = folder.copy(createdAt = Clock.System.now()) + val now = Clock.System.now() + val folder = + folder.copy( + id = UUID.randomUUID().toString(), + createdAt = now, + updatedAt = now, + ) return repo.createFolder(folder) } } diff --git a/domain/src/main/java/com/itlab/domain/usecase/CreateNoteUseCase.kt b/domain/src/main/java/com/itlab/domain/usecase/CreateNoteUseCase.kt index fdc390a..ac3cc73 100644 --- a/domain/src/main/java/com/itlab/domain/usecase/CreateNoteUseCase.kt +++ b/domain/src/main/java/com/itlab/domain/usecase/CreateNoteUseCase.kt @@ -3,12 +3,20 @@ package com.itlab.domain.usecase import com.itlab.domain.model.Note import com.itlab.domain.repository.NotesRepository import kotlinx.datetime.Clock +import java.util.UUID class CreateNoteUseCase( private val repo: NotesRepository, ) { suspend operator fun invoke(note: Note): String { - val note = note.copy(createdAt = Clock.System.now()) + val now = Clock.System.now() + + val note = + note.copy( + id = UUID.randomUUID().toString(), + createdAt = now, + updatedAt = now, + ) return repo.createNote(note) } } diff --git a/domain/src/test/java/com/itlab/domain/FolderUseCasesTest.kt b/domain/src/test/java/com/itlab/domain/FolderUseCasesTest.kt index fbe465b..e66038c 100644 --- a/domain/src/test/java/com/itlab/domain/FolderUseCasesTest.kt +++ b/domain/src/test/java/com/itlab/domain/FolderUseCasesTest.kt @@ -58,11 +58,11 @@ class FolderUseCasesTest { val create = CreateFolderUseCase(repo) val get = GetFolderUseCase(repo) - val folder = NoteFolder(id = "1", name = "Test") + val folder = NoteFolder(name = "Test") - create(folder) + val id = create(folder) - val result = get("1") + val result = get(id) assertEquals("Test", result?.name) } @@ -76,13 +76,16 @@ class FolderUseCasesTest { val update = UpdateFolderUseCase(repo) val get = GetFolderUseCase(repo) - val folder = NoteFolder(id = "1", name = "Old") - create(folder) + val folder = NoteFolder(name = "Old") - val updated = folder.copy(name = "New") + val id = create(folder) + + val created = get(id)!! + + val updated = created.copy(name = "New") update(updated) - val result = get("1") + val result = get(id) assertEquals("New", result?.name) } @@ -96,12 +99,13 @@ class FolderUseCasesTest { val delete = DeleteFolderUseCase(repo) val get = GetFolderUseCase(repo) - val folder = NoteFolder(id = "1", name = "Test") - create(folder) + val folder = NoteFolder(name = "Test") + + val id = create(folder) - delete("1") + delete(id) - val result = get("1") + val result = get(id) assertNull(result) } @@ -113,7 +117,7 @@ class FolderUseCasesTest { val create = CreateFolderUseCase(repo) val observe = ObserveFoldersUseCase(repo) - create(NoteFolder(id = "1", name = "A")) + create(NoteFolder(name = "A")) val list = observe().first() diff --git a/domain/src/test/java/com/itlab/domain/NoteUseCasesTest.kt b/domain/src/test/java/com/itlab/domain/NoteUseCasesTest.kt index be3d572..5cc745a 100644 --- a/domain/src/test/java/com/itlab/domain/NoteUseCasesTest.kt +++ b/domain/src/test/java/com/itlab/domain/NoteUseCasesTest.kt @@ -77,19 +77,21 @@ class NoteUseCasesTest { val delete = DeleteNoteUseCase(repo) val get = GetNoteUseCase(repo) - val note = Note(id = "n1", title = "A") + val note = Note(title = "A") - create(note) + val id = create(note) - val updated = note.copy(title = "B") + val created = get(id)!! + + val updated = created.copy(title = "B") update(updated) - val result = get("n1") + val result = get(id) assertEquals("B", result?.title) - delete("n1") + delete(id) - val result2 = get("n1") + val result2 = get(id) assertNull(result2) } @@ -105,12 +107,13 @@ class NoteUseCasesTest { val folder = NoteFolder(id = "f1", name = "Folder") folderRepo.createFolder(folder) - val note = Note(id = "n1", title = "Note") - createNote(note) + val note = Note(title = "Note") + + val noteId = createNote(note) - move("f1", "n1") + move("f1", noteId) - val updated = notesRepo.getNoteById("n1") + val updated = notesRepo.getNoteById(noteId) assertEquals("f1", updated?.folderId) } @@ -122,8 +125,7 @@ class NoteUseCasesTest { val observe = ObserveNotesUseCase(repo) val create = CreateNoteUseCase(repo) - create(Note(id = "n1", title = "Test")) - + create(Note(title = "Test")) val list = observe().first() assertEquals(1, list.size) From ec29ddace75504ba89b58eb7be8d83588eb4ff6d Mon Sep 17 00:00:00 2001 From: lyzlovazlata Date: Sat, 11 Apr 2026 11:07:48 +0300 Subject: [PATCH 2/5] back to 37 sdk --- ai/build.gradle.kts | 2 +- app/build.gradle.kts | 2 +- data/build.gradle.kts | 3 ++- domain/build.gradle.kts | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/ai/build.gradle.kts b/ai/build.gradle.kts index 67d1eee..2218887 100644 --- a/ai/build.gradle.kts +++ b/ai/build.gradle.kts @@ -7,7 +7,7 @@ plugins { android { namespace = "com.itlab.ai" compileSdk { - version = preview("CinnamonBun") + version = release(37) } defaultConfig { diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 782cb25..1bbae64 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -8,7 +8,7 @@ plugins { android { namespace = "com.itlab.notes" compileSdk { - version = preview("CinnamonBun") + version = release(37) } defaultConfig { diff --git a/data/build.gradle.kts b/data/build.gradle.kts index 979654b..ca92b3a 100644 --- a/data/build.gradle.kts +++ b/data/build.gradle.kts @@ -8,7 +8,7 @@ plugins { android { namespace = "com.itlab.data" - compileSdkPreview = "CinnamonBun" + compileSdk = 37 defaultConfig { minSdk = 33 @@ -31,6 +31,7 @@ android { sourceCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17 } + compileSdkMinor = 0 } kotlin { diff --git a/domain/build.gradle.kts b/domain/build.gradle.kts index b74a693..f9bed20 100644 --- a/domain/build.gradle.kts +++ b/domain/build.gradle.kts @@ -8,7 +8,7 @@ plugins { android { namespace = "com.itlab.domain" compileSdk { - version = preview("CinnamonBun") + version = release(37) } defaultConfig { From 39614def5179b882a1626434a46f30256d2ac84f Mon Sep 17 00:00:00 2001 From: lyzlovazlata Date: Sat, 11 Apr 2026 11:44:01 +0300 Subject: [PATCH 3/5] change packages sorting --- .../{ => usecase}/aiusecase/SuggestSummaryUseCase.kt | 2 +- .../{ => usecase}/aiusecase/SuggestTagsUseCase.kt | 2 +- .../{ => folderusecase}/CreateFolderUseCase.kt | 2 +- .../{ => folderusecase}/DeleteFolderUseCase.kt | 2 +- .../usecase/{ => folderusecase}/GetFolderUseCase.kt | 2 +- .../{ => folderusecase}/ObserveFoldersUseCase.kt | 2 +- .../{ => folderusecase}/UpdateFolderUseCase.kt | 2 +- .../noteusecase}/ApplySummaryUseCase.kt | 5 +++-- .../noteusecase}/ApplyTagsUseCase.kt | 5 +++-- .../usecase/{ => noteusecase}/CreateNoteUseCase.kt | 2 +- .../usecase/{ => noteusecase}/DeleteNoteUseCase.kt | 2 +- .../usecase/{ => noteusecase}/GetNoteUseCase.kt | 2 +- .../{ => noteusecase}/MoveNoteToFolderUseCase.kt | 2 +- .../{ => noteusecase}/ObserveNotesByFolderUseCase.kt | 2 +- .../usecase/{ => noteusecase}/ObserveNotesUseCase.kt | 2 +- .../usecase/{ => noteusecase}/UpdateNoteUseCase.kt | 2 +- .../src/test/java/com/itlab/domain/AIUseCasesTest.kt | 8 ++++---- .../test/java/com/itlab/domain/FolderUseCasesTest.kt | 10 +++++----- .../test/java/com/itlab/domain/NoteUseCasesTest.kt | 12 ++++++------ 19 files changed, 35 insertions(+), 33 deletions(-) rename domain/src/main/java/com/itlab/domain/{ => usecase}/aiusecase/SuggestSummaryUseCase.kt (94%) rename domain/src/main/java/com/itlab/domain/{ => usecase}/aiusecase/SuggestTagsUseCase.kt (96%) rename domain/src/main/java/com/itlab/domain/usecase/{ => folderusecase}/CreateFolderUseCase.kt (92%) rename domain/src/main/java/com/itlab/domain/usecase/{ => folderusecase}/DeleteFolderUseCase.kt (82%) rename domain/src/main/java/com/itlab/domain/usecase/{ => folderusecase}/GetFolderUseCase.kt (84%) rename domain/src/main/java/com/itlab/domain/usecase/{ => folderusecase}/ObserveFoldersUseCase.kt (85%) rename domain/src/main/java/com/itlab/domain/usecase/{ => folderusecase}/UpdateFolderUseCase.kt (88%) rename domain/src/main/java/com/itlab/domain/{aiusecase => usecase/noteusecase}/ApplySummaryUseCase.kt (83%) rename domain/src/main/java/com/itlab/domain/{aiusecase => usecase/noteusecase}/ApplyTagsUseCase.kt (83%) rename domain/src/main/java/com/itlab/domain/usecase/{ => noteusecase}/CreateNoteUseCase.kt (92%) rename domain/src/main/java/com/itlab/domain/usecase/{ => noteusecase}/DeleteNoteUseCase.kt (82%) rename domain/src/main/java/com/itlab/domain/usecase/{ => noteusecase}/GetNoteUseCase.kt (83%) rename domain/src/main/java/com/itlab/domain/usecase/{ => noteusecase}/MoveNoteToFolderUseCase.kt (91%) rename domain/src/main/java/com/itlab/domain/usecase/{ => noteusecase}/ObserveNotesByFolderUseCase.kt (90%) rename domain/src/main/java/com/itlab/domain/usecase/{ => noteusecase}/ObserveNotesUseCase.kt (85%) rename domain/src/main/java/com/itlab/domain/usecase/{ => noteusecase}/UpdateNoteUseCase.kt (88%) diff --git a/domain/src/main/java/com/itlab/domain/aiusecase/SuggestSummaryUseCase.kt b/domain/src/main/java/com/itlab/domain/usecase/aiusecase/SuggestSummaryUseCase.kt similarity index 94% rename from domain/src/main/java/com/itlab/domain/aiusecase/SuggestSummaryUseCase.kt rename to domain/src/main/java/com/itlab/domain/usecase/aiusecase/SuggestSummaryUseCase.kt index 5c75d4d..985aba8 100644 --- a/domain/src/main/java/com/itlab/domain/aiusecase/SuggestSummaryUseCase.kt +++ b/domain/src/main/java/com/itlab/domain/usecase/aiusecase/SuggestSummaryUseCase.kt @@ -1,4 +1,4 @@ -package com.itlab.domain.aiusecase +package com.itlab.domain.usecase.aiusecase import com.itlab.domain.ai.NoteAiService import com.itlab.domain.model.ContentItem diff --git a/domain/src/main/java/com/itlab/domain/aiusecase/SuggestTagsUseCase.kt b/domain/src/main/java/com/itlab/domain/usecase/aiusecase/SuggestTagsUseCase.kt similarity index 96% rename from domain/src/main/java/com/itlab/domain/aiusecase/SuggestTagsUseCase.kt rename to domain/src/main/java/com/itlab/domain/usecase/aiusecase/SuggestTagsUseCase.kt index 6de701a..2360269 100644 --- a/domain/src/main/java/com/itlab/domain/aiusecase/SuggestTagsUseCase.kt +++ b/domain/src/main/java/com/itlab/domain/usecase/aiusecase/SuggestTagsUseCase.kt @@ -1,4 +1,4 @@ -package com.itlab.domain.aiusecase +package com.itlab.domain.usecase.aiusecase import com.itlab.domain.ai.NoteAiService import com.itlab.domain.model.ContentItem diff --git a/domain/src/main/java/com/itlab/domain/usecase/CreateFolderUseCase.kt b/domain/src/main/java/com/itlab/domain/usecase/folderusecase/CreateFolderUseCase.kt similarity index 92% rename from domain/src/main/java/com/itlab/domain/usecase/CreateFolderUseCase.kt rename to domain/src/main/java/com/itlab/domain/usecase/folderusecase/CreateFolderUseCase.kt index e4d68a7..20a5727 100644 --- a/domain/src/main/java/com/itlab/domain/usecase/CreateFolderUseCase.kt +++ b/domain/src/main/java/com/itlab/domain/usecase/folderusecase/CreateFolderUseCase.kt @@ -1,4 +1,4 @@ -package com.itlab.domain.usecase +package com.itlab.domain.usecase.folderusecase import com.itlab.domain.model.NoteFolder import com.itlab.domain.repository.NoteFolderRepository diff --git a/domain/src/main/java/com/itlab/domain/usecase/DeleteFolderUseCase.kt b/domain/src/main/java/com/itlab/domain/usecase/folderusecase/DeleteFolderUseCase.kt similarity index 82% rename from domain/src/main/java/com/itlab/domain/usecase/DeleteFolderUseCase.kt rename to domain/src/main/java/com/itlab/domain/usecase/folderusecase/DeleteFolderUseCase.kt index 9dd0169..3b18008 100644 --- a/domain/src/main/java/com/itlab/domain/usecase/DeleteFolderUseCase.kt +++ b/domain/src/main/java/com/itlab/domain/usecase/folderusecase/DeleteFolderUseCase.kt @@ -1,4 +1,4 @@ -package com.itlab.domain.usecase +package com.itlab.domain.usecase.folderusecase import com.itlab.domain.repository.NoteFolderRepository diff --git a/domain/src/main/java/com/itlab/domain/usecase/GetFolderUseCase.kt b/domain/src/main/java/com/itlab/domain/usecase/folderusecase/GetFolderUseCase.kt similarity index 84% rename from domain/src/main/java/com/itlab/domain/usecase/GetFolderUseCase.kt rename to domain/src/main/java/com/itlab/domain/usecase/folderusecase/GetFolderUseCase.kt index dbbd872..3519e82 100644 --- a/domain/src/main/java/com/itlab/domain/usecase/GetFolderUseCase.kt +++ b/domain/src/main/java/com/itlab/domain/usecase/folderusecase/GetFolderUseCase.kt @@ -1,4 +1,4 @@ -package com.itlab.domain.usecase +package com.itlab.domain.usecase.folderusecase import com.itlab.domain.model.NoteFolder import com.itlab.domain.repository.NoteFolderRepository diff --git a/domain/src/main/java/com/itlab/domain/usecase/ObserveFoldersUseCase.kt b/domain/src/main/java/com/itlab/domain/usecase/folderusecase/ObserveFoldersUseCase.kt similarity index 85% rename from domain/src/main/java/com/itlab/domain/usecase/ObserveFoldersUseCase.kt rename to domain/src/main/java/com/itlab/domain/usecase/folderusecase/ObserveFoldersUseCase.kt index 92b7a3a..6b814fe 100644 --- a/domain/src/main/java/com/itlab/domain/usecase/ObserveFoldersUseCase.kt +++ b/domain/src/main/java/com/itlab/domain/usecase/folderusecase/ObserveFoldersUseCase.kt @@ -1,4 +1,4 @@ -package com.itlab.domain.usecase +package com.itlab.domain.usecase.folderusecase import com.itlab.domain.model.NoteFolder import com.itlab.domain.repository.NoteFolderRepository diff --git a/domain/src/main/java/com/itlab/domain/usecase/UpdateFolderUseCase.kt b/domain/src/main/java/com/itlab/domain/usecase/folderusecase/UpdateFolderUseCase.kt similarity index 88% rename from domain/src/main/java/com/itlab/domain/usecase/UpdateFolderUseCase.kt rename to domain/src/main/java/com/itlab/domain/usecase/folderusecase/UpdateFolderUseCase.kt index 2539c82..d4ecd78 100644 --- a/domain/src/main/java/com/itlab/domain/usecase/UpdateFolderUseCase.kt +++ b/domain/src/main/java/com/itlab/domain/usecase/folderusecase/UpdateFolderUseCase.kt @@ -1,4 +1,4 @@ -package com.itlab.domain.usecase +package com.itlab.domain.usecase.folderusecase import com.itlab.domain.model.NoteFolder import com.itlab.domain.repository.NoteFolderRepository diff --git a/domain/src/main/java/com/itlab/domain/aiusecase/ApplySummaryUseCase.kt b/domain/src/main/java/com/itlab/domain/usecase/noteusecase/ApplySummaryUseCase.kt similarity index 83% rename from domain/src/main/java/com/itlab/domain/aiusecase/ApplySummaryUseCase.kt rename to domain/src/main/java/com/itlab/domain/usecase/noteusecase/ApplySummaryUseCase.kt index db484de..60c7a19 100644 --- a/domain/src/main/java/com/itlab/domain/aiusecase/ApplySummaryUseCase.kt +++ b/domain/src/main/java/com/itlab/domain/usecase/noteusecase/ApplySummaryUseCase.kt @@ -1,6 +1,7 @@ -package com.itlab.domain.aiusecase +package com.itlab.domain.usecase.noteusecase import com.itlab.domain.repository.NotesRepository +import kotlinx.datetime.Clock class ApplySummaryUseCase( private val repo: NotesRepository, @@ -17,7 +18,7 @@ class ApplySummaryUseCase( note.copy( summary = newSummary, updatedAt = - kotlinx.datetime.Clock.System + Clock.System .now(), ) diff --git a/domain/src/main/java/com/itlab/domain/aiusecase/ApplyTagsUseCase.kt b/domain/src/main/java/com/itlab/domain/usecase/noteusecase/ApplyTagsUseCase.kt similarity index 83% rename from domain/src/main/java/com/itlab/domain/aiusecase/ApplyTagsUseCase.kt rename to domain/src/main/java/com/itlab/domain/usecase/noteusecase/ApplyTagsUseCase.kt index 85e5114..8953f5f 100644 --- a/domain/src/main/java/com/itlab/domain/aiusecase/ApplyTagsUseCase.kt +++ b/domain/src/main/java/com/itlab/domain/usecase/noteusecase/ApplyTagsUseCase.kt @@ -1,6 +1,7 @@ -package com.itlab.domain.aiusecase +package com.itlab.domain.usecase.noteusecase import com.itlab.domain.repository.NotesRepository +import kotlinx.datetime.Clock class ApplyTagsUseCase( private val repo: NotesRepository, @@ -17,7 +18,7 @@ class ApplyTagsUseCase( note.copy( tags = newTags, updatedAt = - kotlinx.datetime.Clock.System + Clock.System .now(), ) diff --git a/domain/src/main/java/com/itlab/domain/usecase/CreateNoteUseCase.kt b/domain/src/main/java/com/itlab/domain/usecase/noteusecase/CreateNoteUseCase.kt similarity index 92% rename from domain/src/main/java/com/itlab/domain/usecase/CreateNoteUseCase.kt rename to domain/src/main/java/com/itlab/domain/usecase/noteusecase/CreateNoteUseCase.kt index ac3cc73..49807b9 100644 --- a/domain/src/main/java/com/itlab/domain/usecase/CreateNoteUseCase.kt +++ b/domain/src/main/java/com/itlab/domain/usecase/noteusecase/CreateNoteUseCase.kt @@ -1,4 +1,4 @@ -package com.itlab.domain.usecase +package com.itlab.domain.usecase.noteusecase import com.itlab.domain.model.Note import com.itlab.domain.repository.NotesRepository diff --git a/domain/src/main/java/com/itlab/domain/usecase/DeleteNoteUseCase.kt b/domain/src/main/java/com/itlab/domain/usecase/noteusecase/DeleteNoteUseCase.kt similarity index 82% rename from domain/src/main/java/com/itlab/domain/usecase/DeleteNoteUseCase.kt rename to domain/src/main/java/com/itlab/domain/usecase/noteusecase/DeleteNoteUseCase.kt index 65e8b8a..4a287eb 100644 --- a/domain/src/main/java/com/itlab/domain/usecase/DeleteNoteUseCase.kt +++ b/domain/src/main/java/com/itlab/domain/usecase/noteusecase/DeleteNoteUseCase.kt @@ -1,4 +1,4 @@ -package com.itlab.domain.usecase +package com.itlab.domain.usecase.noteusecase import com.itlab.domain.repository.NotesRepository diff --git a/domain/src/main/java/com/itlab/domain/usecase/GetNoteUseCase.kt b/domain/src/main/java/com/itlab/domain/usecase/noteusecase/GetNoteUseCase.kt similarity index 83% rename from domain/src/main/java/com/itlab/domain/usecase/GetNoteUseCase.kt rename to domain/src/main/java/com/itlab/domain/usecase/noteusecase/GetNoteUseCase.kt index bec0c5a..9901149 100644 --- a/domain/src/main/java/com/itlab/domain/usecase/GetNoteUseCase.kt +++ b/domain/src/main/java/com/itlab/domain/usecase/noteusecase/GetNoteUseCase.kt @@ -1,4 +1,4 @@ -package com.itlab.domain.usecase +package com.itlab.domain.usecase.noteusecase import com.itlab.domain.model.Note import com.itlab.domain.repository.NotesRepository diff --git a/domain/src/main/java/com/itlab/domain/usecase/MoveNoteToFolderUseCase.kt b/domain/src/main/java/com/itlab/domain/usecase/noteusecase/MoveNoteToFolderUseCase.kt similarity index 91% rename from domain/src/main/java/com/itlab/domain/usecase/MoveNoteToFolderUseCase.kt rename to domain/src/main/java/com/itlab/domain/usecase/noteusecase/MoveNoteToFolderUseCase.kt index c5f0265..ed711a1 100644 --- a/domain/src/main/java/com/itlab/domain/usecase/MoveNoteToFolderUseCase.kt +++ b/domain/src/main/java/com/itlab/domain/usecase/noteusecase/MoveNoteToFolderUseCase.kt @@ -1,4 +1,4 @@ -package com.itlab.domain.usecase +package com.itlab.domain.usecase.noteusecase import com.itlab.domain.repository.NotesRepository import kotlinx.datetime.Clock diff --git a/domain/src/main/java/com/itlab/domain/usecase/ObserveNotesByFolderUseCase.kt b/domain/src/main/java/com/itlab/domain/usecase/noteusecase/ObserveNotesByFolderUseCase.kt similarity index 90% rename from domain/src/main/java/com/itlab/domain/usecase/ObserveNotesByFolderUseCase.kt rename to domain/src/main/java/com/itlab/domain/usecase/noteusecase/ObserveNotesByFolderUseCase.kt index 3634333..fa67715 100644 --- a/domain/src/main/java/com/itlab/domain/usecase/ObserveNotesByFolderUseCase.kt +++ b/domain/src/main/java/com/itlab/domain/usecase/noteusecase/ObserveNotesByFolderUseCase.kt @@ -1,4 +1,4 @@ -package com.itlab.domain.usecase +package com.itlab.domain.usecase.noteusecase import com.itlab.domain.model.Note import com.itlab.domain.repository.NotesRepository diff --git a/domain/src/main/java/com/itlab/domain/usecase/ObserveNotesUseCase.kt b/domain/src/main/java/com/itlab/domain/usecase/noteusecase/ObserveNotesUseCase.kt similarity index 85% rename from domain/src/main/java/com/itlab/domain/usecase/ObserveNotesUseCase.kt rename to domain/src/main/java/com/itlab/domain/usecase/noteusecase/ObserveNotesUseCase.kt index 1fbfa3b..90c9c17 100644 --- a/domain/src/main/java/com/itlab/domain/usecase/ObserveNotesUseCase.kt +++ b/domain/src/main/java/com/itlab/domain/usecase/noteusecase/ObserveNotesUseCase.kt @@ -1,4 +1,4 @@ -package com.itlab.domain.usecase +package com.itlab.domain.usecase.noteusecase import com.itlab.domain.model.Note import com.itlab.domain.repository.NotesRepository diff --git a/domain/src/main/java/com/itlab/domain/usecase/UpdateNoteUseCase.kt b/domain/src/main/java/com/itlab/domain/usecase/noteusecase/UpdateNoteUseCase.kt similarity index 88% rename from domain/src/main/java/com/itlab/domain/usecase/UpdateNoteUseCase.kt rename to domain/src/main/java/com/itlab/domain/usecase/noteusecase/UpdateNoteUseCase.kt index f7470ee..d7ccb50 100644 --- a/domain/src/main/java/com/itlab/domain/usecase/UpdateNoteUseCase.kt +++ b/domain/src/main/java/com/itlab/domain/usecase/noteusecase/UpdateNoteUseCase.kt @@ -1,4 +1,4 @@ -package com.itlab.domain.usecase +package com.itlab.domain.usecase.noteusecase import com.itlab.domain.model.Note import com.itlab.domain.repository.NotesRepository diff --git a/domain/src/test/java/com/itlab/domain/AIUseCasesTest.kt b/domain/src/test/java/com/itlab/domain/AIUseCasesTest.kt index 97d4c3b..19e53af 100644 --- a/domain/src/test/java/com/itlab/domain/AIUseCasesTest.kt +++ b/domain/src/test/java/com/itlab/domain/AIUseCasesTest.kt @@ -1,14 +1,14 @@ package com.itlab.domain import com.itlab.domain.ai.NoteAiService -import com.itlab.domain.aiusecase.ApplySummaryUseCase -import com.itlab.domain.aiusecase.ApplyTagsUseCase -import com.itlab.domain.aiusecase.SuggestSummaryUseCase -import com.itlab.domain.aiusecase.SuggestTagsUseCase import com.itlab.domain.model.ContentItem import com.itlab.domain.model.DataSource import com.itlab.domain.model.Note import com.itlab.domain.repository.NotesRepository +import com.itlab.domain.usecase.aiusecase.SuggestSummaryUseCase +import com.itlab.domain.usecase.aiusecase.SuggestTagsUseCase +import com.itlab.domain.usecase.noteusecase.ApplySummaryUseCase +import com.itlab.domain.usecase.noteusecase.ApplyTagsUseCase import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.map diff --git a/domain/src/test/java/com/itlab/domain/FolderUseCasesTest.kt b/domain/src/test/java/com/itlab/domain/FolderUseCasesTest.kt index e66038c..8650a4e 100644 --- a/domain/src/test/java/com/itlab/domain/FolderUseCasesTest.kt +++ b/domain/src/test/java/com/itlab/domain/FolderUseCasesTest.kt @@ -2,11 +2,11 @@ package com.itlab.domain import com.itlab.domain.model.NoteFolder import com.itlab.domain.repository.NoteFolderRepository -import com.itlab.domain.usecase.CreateFolderUseCase -import com.itlab.domain.usecase.DeleteFolderUseCase -import com.itlab.domain.usecase.GetFolderUseCase -import com.itlab.domain.usecase.ObserveFoldersUseCase -import com.itlab.domain.usecase.UpdateFolderUseCase +import com.itlab.domain.usecase.folderusecase.CreateFolderUseCase +import com.itlab.domain.usecase.folderusecase.DeleteFolderUseCase +import com.itlab.domain.usecase.folderusecase.GetFolderUseCase +import com.itlab.domain.usecase.folderusecase.ObserveFoldersUseCase +import com.itlab.domain.usecase.folderusecase.UpdateFolderUseCase import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.first import kotlinx.coroutines.runBlocking diff --git a/domain/src/test/java/com/itlab/domain/NoteUseCasesTest.kt b/domain/src/test/java/com/itlab/domain/NoteUseCasesTest.kt index 5cc745a..ee5587e 100644 --- a/domain/src/test/java/com/itlab/domain/NoteUseCasesTest.kt +++ b/domain/src/test/java/com/itlab/domain/NoteUseCasesTest.kt @@ -4,12 +4,12 @@ import com.itlab.domain.model.Note import com.itlab.domain.model.NoteFolder import com.itlab.domain.repository.NoteFolderRepository import com.itlab.domain.repository.NotesRepository -import com.itlab.domain.usecase.CreateNoteUseCase -import com.itlab.domain.usecase.DeleteNoteUseCase -import com.itlab.domain.usecase.GetNoteUseCase -import com.itlab.domain.usecase.MoveNoteToFolderUseCase -import com.itlab.domain.usecase.ObserveNotesUseCase -import com.itlab.domain.usecase.UpdateNoteUseCase +import com.itlab.domain.usecase.noteusecase.CreateNoteUseCase +import com.itlab.domain.usecase.noteusecase.DeleteNoteUseCase +import com.itlab.domain.usecase.noteusecase.GetNoteUseCase +import com.itlab.domain.usecase.noteusecase.MoveNoteToFolderUseCase +import com.itlab.domain.usecase.noteusecase.ObserveNotesUseCase +import com.itlab.domain.usecase.noteusecase.UpdateNoteUseCase import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.first import kotlinx.coroutines.runBlocking From 1920e456a6adae916825b0c91b1b123ecbb0423b Mon Sep 17 00:00:00 2001 From: lyzlovazlata Date: Sat, 11 Apr 2026 12:33:30 +0300 Subject: [PATCH 4/5] Add some note usecases, covered with tests --- .../usecase/noteusecase/AddTagUseCase.kt | 25 +++ .../usecase/noteusecase/DeleteTagUseCase.kt | 25 +++ .../noteusecase/DuplicateNoteUseCase.kt | 26 +++ .../noteusecase/GetAllFavoritesUseCase.kt | 15 ++ .../noteusecase/SwitchFavoriteUseCase.kt | 20 ++ .../java/com/itlab/domain/NoteUseCasesTest.kt | 203 ++++++++++++++++++ 6 files changed, 314 insertions(+) create mode 100644 domain/src/main/java/com/itlab/domain/usecase/noteusecase/AddTagUseCase.kt create mode 100644 domain/src/main/java/com/itlab/domain/usecase/noteusecase/DeleteTagUseCase.kt create mode 100644 domain/src/main/java/com/itlab/domain/usecase/noteusecase/DuplicateNoteUseCase.kt create mode 100644 domain/src/main/java/com/itlab/domain/usecase/noteusecase/GetAllFavoritesUseCase.kt create mode 100644 domain/src/main/java/com/itlab/domain/usecase/noteusecase/SwitchFavoriteUseCase.kt diff --git a/domain/src/main/java/com/itlab/domain/usecase/noteusecase/AddTagUseCase.kt b/domain/src/main/java/com/itlab/domain/usecase/noteusecase/AddTagUseCase.kt new file mode 100644 index 0000000..f81614f --- /dev/null +++ b/domain/src/main/java/com/itlab/domain/usecase/noteusecase/AddTagUseCase.kt @@ -0,0 +1,25 @@ +package com.itlab.domain.usecase.noteusecase + +import com.itlab.domain.repository.NotesRepository +import kotlinx.datetime.Clock + +class AddTagUseCase( + private val repo: NotesRepository, +) { + suspend operator fun invoke( + noteId: String, + tagToAdd: String, + ) { + val note = + repo.getNoteById(noteId) + ?: throw IllegalArgumentException("Note not found: $noteId") + + val updated = + note.copy( + tags = note.tags + tagToAdd, + updatedAt = Clock.System.now(), + ) + + repo.updateNote(updated) + } +} diff --git a/domain/src/main/java/com/itlab/domain/usecase/noteusecase/DeleteTagUseCase.kt b/domain/src/main/java/com/itlab/domain/usecase/noteusecase/DeleteTagUseCase.kt new file mode 100644 index 0000000..0adeea5 --- /dev/null +++ b/domain/src/main/java/com/itlab/domain/usecase/noteusecase/DeleteTagUseCase.kt @@ -0,0 +1,25 @@ +package com.itlab.domain.usecase.noteusecase + +import com.itlab.domain.repository.NotesRepository +import kotlinx.datetime.Clock + +class DeleteTagUseCase( + private val repo: NotesRepository, +) { + suspend operator fun invoke( + noteId: String, + tagToDel: String, + ) { + val note = + repo.getNoteById(noteId) + ?: throw IllegalArgumentException("Note not found: $noteId") + + val updated = + note.copy( + tags = note.tags - tagToDel, + updatedAt = Clock.System.now(), + ) + + repo.updateNote(updated) + } +} diff --git a/domain/src/main/java/com/itlab/domain/usecase/noteusecase/DuplicateNoteUseCase.kt b/domain/src/main/java/com/itlab/domain/usecase/noteusecase/DuplicateNoteUseCase.kt new file mode 100644 index 0000000..4225e5f --- /dev/null +++ b/domain/src/main/java/com/itlab/domain/usecase/noteusecase/DuplicateNoteUseCase.kt @@ -0,0 +1,26 @@ +package com.itlab.domain.usecase.noteusecase + +import com.itlab.domain.repository.NotesRepository +import kotlinx.datetime.Clock +import java.util.UUID + +class DuplicateNoteUseCase( + private val repo: NotesRepository, +) { + suspend operator fun invoke(noteId: String): String { + val note = + repo.getNoteById(noteId) + ?: throw IllegalArgumentException("Note not found: $noteId") + + val now = Clock.System.now() + val duplicated = + note.copy( + id = UUID.randomUUID().toString(), + title = if (note.title.isBlank()) "Copy" else "${note.title} Copy", + createdAt = now, + updatedAt = now, + ) + + return repo.createNote(duplicated) + } +} diff --git a/domain/src/main/java/com/itlab/domain/usecase/noteusecase/GetAllFavoritesUseCase.kt b/domain/src/main/java/com/itlab/domain/usecase/noteusecase/GetAllFavoritesUseCase.kt new file mode 100644 index 0000000..6008bea --- /dev/null +++ b/domain/src/main/java/com/itlab/domain/usecase/noteusecase/GetAllFavoritesUseCase.kt @@ -0,0 +1,15 @@ +package com.itlab.domain.usecase.noteusecase + +import com.itlab.domain.model.Note +import com.itlab.domain.repository.NotesRepository +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map + +class GetAllFavoritesUseCase( + private val repo: NotesRepository, +) { + operator fun invoke(): Flow> = + repo.observeNotes().map { notes -> + notes.filter { it.isFavorite } + } +} diff --git a/domain/src/main/java/com/itlab/domain/usecase/noteusecase/SwitchFavoriteUseCase.kt b/domain/src/main/java/com/itlab/domain/usecase/noteusecase/SwitchFavoriteUseCase.kt new file mode 100644 index 0000000..d0ec44c --- /dev/null +++ b/domain/src/main/java/com/itlab/domain/usecase/noteusecase/SwitchFavoriteUseCase.kt @@ -0,0 +1,20 @@ +package com.itlab.domain.usecase.noteusecase + +import com.itlab.domain.repository.NotesRepository + +class SwitchFavoriteUseCase( + private val repo: NotesRepository, +) { + suspend operator fun invoke(noteId: String) { + val note = + repo.getNoteById(noteId) + ?: throw IllegalArgumentException("Note not found") + + val updatedNote = + note.copy( + isFavorite = !note.isFavorite, + ) + + repo.updateNote(updatedNote) + } +} diff --git a/domain/src/test/java/com/itlab/domain/NoteUseCasesTest.kt b/domain/src/test/java/com/itlab/domain/NoteUseCasesTest.kt index ee5587e..64f31ee 100644 --- a/domain/src/test/java/com/itlab/domain/NoteUseCasesTest.kt +++ b/domain/src/test/java/com/itlab/domain/NoteUseCasesTest.kt @@ -4,17 +4,23 @@ import com.itlab.domain.model.Note import com.itlab.domain.model.NoteFolder import com.itlab.domain.repository.NoteFolderRepository import com.itlab.domain.repository.NotesRepository +import com.itlab.domain.usecase.noteusecase.AddTagUseCase import com.itlab.domain.usecase.noteusecase.CreateNoteUseCase import com.itlab.domain.usecase.noteusecase.DeleteNoteUseCase +import com.itlab.domain.usecase.noteusecase.DeleteTagUseCase +import com.itlab.domain.usecase.noteusecase.DuplicateNoteUseCase +import com.itlab.domain.usecase.noteusecase.GetAllFavoritesUseCase import com.itlab.domain.usecase.noteusecase.GetNoteUseCase import com.itlab.domain.usecase.noteusecase.MoveNoteToFolderUseCase import com.itlab.domain.usecase.noteusecase.ObserveNotesUseCase +import com.itlab.domain.usecase.noteusecase.SwitchFavoriteUseCase import com.itlab.domain.usecase.noteusecase.UpdateNoteUseCase import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.first import kotlinx.coroutines.runBlocking import org.junit.Assert.assertEquals import org.junit.Assert.assertNull +import org.junit.Assert.fail import org.junit.Test class NoteUseCasesTest { @@ -130,4 +136,201 @@ class NoteUseCasesTest { assertEquals(1, list.size) } + + @Test + fun addTag_addsTagToNote() = + runBlocking { + val repo = FakeNotesRepo() + val useCase = AddTagUseCase(repo) + + val note = + Note( + id = "n1", + title = "Test", + tags = setOf("old"), + ) + repo.createNote(note) + + useCase("n1", "new-tag") + + val updated = repo.getNoteById("n1") + + assertEquals(setOf("old", "new-tag"), updated?.tags) + } + + @Test + fun addTag_throwsIfNoteNotFound() = + runBlocking { + val repo = FakeNotesRepo() + val useCase = AddTagUseCase(repo) + + try { + useCase("missing_id", "tag") + fail("Expected IllegalArgumentException") + } catch (e: IllegalArgumentException) { + assertEquals("Note not found: missing_id", e.message) + } + } + + @Test + fun deleteTag_removesTagFromNote() = + runBlocking { + val repo = FakeNotesRepo() + val useCase = DeleteTagUseCase(repo) + + val note = + Note( + id = "n2", + title = "Test", + tags = setOf("old", "remove-me"), + ) + repo.createNote(note) + + useCase("n2", "remove-me") + + val updated = repo.getNoteById("n2") + + assertEquals(setOf("old"), updated?.tags) + } + + @Test + fun deleteTag_throwsIfNoteNotFound() = + runBlocking { + val repo = FakeNotesRepo() + val useCase = DeleteTagUseCase(repo) + + try { + useCase("missing_id", "tag") + fail("Expected IllegalArgumentException") + } catch (e: IllegalArgumentException) { + assertEquals("Note not found: missing_id", e.message) + } + } + + @Test + fun duplicateNote_createsCopyWithNewIdAndCopiedTitle() = + runBlocking { + val repo = FakeNotesRepo() + val useCase = DuplicateNoteUseCase(repo) + + val original = + Note( + id = "n3", + title = "Hello", + tags = setOf("kotlin"), + isFavorite = true, + summary = "summary", + ) + repo.createNote(original) + + val newId = useCase("n3") + + val duplicated = repo.getNoteById(newId) + + assertEquals(true, duplicated != null) + assertEquals("Hello Copy", duplicated?.title) + assertEquals(setOf("kotlin"), duplicated?.tags) + assertEquals(true, duplicated?.isFavorite) + assertEquals("summary", duplicated?.summary) + assertEquals("n3", original.id) + assertEquals(false, original.id == newId) + } + + @Test + fun duplicateNote_usesCopyWhenTitleBlank() = + runBlocking { + val repo = FakeNotesRepo() + val useCase = DuplicateNoteUseCase(repo) + + val original = + Note( + id = "n4", + title = " ", + ) + repo.createNote(original) + + val newId = useCase("n4") + + val duplicated = repo.getNoteById(newId) + + assertEquals("Copy", duplicated?.title) + } + + @Test + fun duplicateNote_throwsIfNoteNotFound() = + runBlocking { + val repo = FakeNotesRepo() + val useCase = DuplicateNoteUseCase(repo) + + try { + useCase("missing_id") + fail("Expected IllegalArgumentException") + } catch (e: IllegalArgumentException) { + assertEquals("Note not found: missing_id", e.message) + } + } + + @Test + fun getAllFavorites_returnsOnlyFavoriteNotes() = + runBlocking { + val repo = FakeNotesRepo() + val useCase = GetAllFavoritesUseCase(repo) + + repo.createNote( + Note( + id = "n5", + title = "A", + isFavorite = true, + ), + ) + repo.createNote( + Note( + id = "n6", + title = "B", + isFavorite = false, + ), + ) + + val list = useCase().first() + + assertEquals(1, list.size) + assertEquals("n5", list.first().id) + } + + @Test + fun switchFavorite_turnsFavoriteOnAndOff() = + runBlocking { + val repo = FakeNotesRepo() + val useCase = SwitchFavoriteUseCase(repo) + + val note = + Note( + id = "n7", + title = "Fav", + isFavorite = false, + ) + repo.createNote(note) + + useCase("n7") + val afterFirstSwitch = repo.getNoteById("n7") + assertEquals(true, afterFirstSwitch?.isFavorite) + + useCase("n7") + val afterSecondSwitch = repo.getNoteById("n7") + assertEquals(false, afterSecondSwitch?.isFavorite) + } + + @Test + fun switchFavorite_throwsIfNoteNotFound() = + runBlocking { + val repo = FakeNotesRepo() + val useCase = SwitchFavoriteUseCase(repo) + + try { + useCase("missing_id") + fail("Expected IllegalArgumentException") + } catch (e: IllegalArgumentException) { + assertEquals("Note not found", e.message) + } + } } From ab61af9a4ec0f40f30680f5c6020fc7529f8ccc9 Mon Sep 17 00:00:00 2001 From: lyzlovazlata Date: Sat, 11 Apr 2026 13:34:30 +0300 Subject: [PATCH 5/5] Change Content Item model - add id, add item use cases, fix duplicate note for new model, covered with tests --- .../main/java/com/itlab/domain/model/Note.kt | 6 + .../contentusecase/AddContentItemUseCase.kt | 30 ++++ .../CreateContentItemUseCase.kt | 14 ++ .../DeleteContentItemUseCase.kt | 24 +++ .../contentusecase/GetContentItemUseCase.kt | 19 +++ .../noteusecase/DuplicateNoteUseCase.kt | 11 +- .../java/com/itlab/domain/AIUseCasesTest.kt | 18 ++- .../itlab/domain/ContentItemUseCaseTest.kt | 148 ++++++++++++++++++ .../test/java/com/itlab/domain/NoteTest.kt | 12 +- 9 files changed, 270 insertions(+), 12 deletions(-) create mode 100644 domain/src/main/java/com/itlab/domain/usecase/contentusecase/AddContentItemUseCase.kt create mode 100644 domain/src/main/java/com/itlab/domain/usecase/contentusecase/CreateContentItemUseCase.kt create mode 100644 domain/src/main/java/com/itlab/domain/usecase/contentusecase/DeleteContentItemUseCase.kt create mode 100644 domain/src/main/java/com/itlab/domain/usecase/contentusecase/GetContentItemUseCase.kt create mode 100644 domain/src/test/java/com/itlab/domain/ContentItemUseCaseTest.kt diff --git a/domain/src/main/java/com/itlab/domain/model/Note.kt b/domain/src/main/java/com/itlab/domain/model/Note.kt index c05d641..dee3c50 100644 --- a/domain/src/main/java/com/itlab/domain/model/Note.kt +++ b/domain/src/main/java/com/itlab/domain/model/Note.kt @@ -27,14 +27,18 @@ data class DataSource( @Serializable sealed class ContentItem { + abstract val id: String + @Serializable data class Text( + override val id: String = UUID.randomUUID().toString(), val text: String, val format: TextFormat = TextFormat.PLAIN, ) : ContentItem() @Serializable data class Image( + override val id: String = UUID.randomUUID().toString(), val source: DataSource, val mimeType: String, val width: Int? = null, @@ -43,6 +47,7 @@ sealed class ContentItem { @Serializable data class File( + override val id: String = UUID.randomUUID().toString(), val source: DataSource, val mimeType: String, val name: String, @@ -51,6 +56,7 @@ sealed class ContentItem { @Serializable data class Link( + override val id: String = UUID.randomUUID().toString(), val url: String, val title: String? = null, ) : ContentItem() diff --git a/domain/src/main/java/com/itlab/domain/usecase/contentusecase/AddContentItemUseCase.kt b/domain/src/main/java/com/itlab/domain/usecase/contentusecase/AddContentItemUseCase.kt new file mode 100644 index 0000000..eee77c8 --- /dev/null +++ b/domain/src/main/java/com/itlab/domain/usecase/contentusecase/AddContentItemUseCase.kt @@ -0,0 +1,30 @@ +package com.itlab.domain.usecase.contentusecase + +import com.itlab.domain.model.ContentItem +import com.itlab.domain.repository.NotesRepository +import kotlinx.datetime.Clock + +class AddContentItemUseCase( + private val notesRepository: NotesRepository, +) { + suspend operator fun invoke( + noteId: String, + item: ContentItem, + ) { + require(item.id.isNotBlank()) { + "ContentItem id must be created before adding to note" + } + + val note = + notesRepository.getNoteById(noteId) + ?: throw IllegalArgumentException("Note not found: $noteId") + + val updated = + note.copy( + contentItems = note.contentItems + item, + updatedAt = Clock.System.now(), + ) + + notesRepository.updateNote(updated) + } +} diff --git a/domain/src/main/java/com/itlab/domain/usecase/contentusecase/CreateContentItemUseCase.kt b/domain/src/main/java/com/itlab/domain/usecase/contentusecase/CreateContentItemUseCase.kt new file mode 100644 index 0000000..14c4dd6 --- /dev/null +++ b/domain/src/main/java/com/itlab/domain/usecase/contentusecase/CreateContentItemUseCase.kt @@ -0,0 +1,14 @@ +package com.itlab.domain.usecase.contentusecase + +import com.itlab.domain.model.ContentItem +import java.util.UUID + +class CreateContentItemUseCase { + operator fun invoke(item: ContentItem): ContentItem = + when (item) { + is ContentItem.Text -> item.copy(id = UUID.randomUUID().toString()) + is ContentItem.Image -> item.copy(id = UUID.randomUUID().toString()) + is ContentItem.File -> item.copy(id = UUID.randomUUID().toString()) + is ContentItem.Link -> item.copy(id = UUID.randomUUID().toString()) + } +} diff --git a/domain/src/main/java/com/itlab/domain/usecase/contentusecase/DeleteContentItemUseCase.kt b/domain/src/main/java/com/itlab/domain/usecase/contentusecase/DeleteContentItemUseCase.kt new file mode 100644 index 0000000..8ce3d3e --- /dev/null +++ b/domain/src/main/java/com/itlab/domain/usecase/contentusecase/DeleteContentItemUseCase.kt @@ -0,0 +1,24 @@ +package com.itlab.domain.usecase.contentusecase + +import com.itlab.domain.repository.NotesRepository +import kotlinx.datetime.Clock + +class DeleteContentItemUseCase( + private val notesRepository: NotesRepository, +) { + suspend operator fun invoke( + noteId: String, + itemId: String, + ) { + val note = + notesRepository.getNoteById(noteId) + ?: throw IllegalArgumentException("Note not found: $noteId") + + val updated = + note.copy( + contentItems = note.contentItems.filterNot { it.id == itemId }, + updatedAt = Clock.System.now(), + ) + notesRepository.updateNote(updated) + } +} diff --git a/domain/src/main/java/com/itlab/domain/usecase/contentusecase/GetContentItemUseCase.kt b/domain/src/main/java/com/itlab/domain/usecase/contentusecase/GetContentItemUseCase.kt new file mode 100644 index 0000000..1159d8d --- /dev/null +++ b/domain/src/main/java/com/itlab/domain/usecase/contentusecase/GetContentItemUseCase.kt @@ -0,0 +1,19 @@ +package com.itlab.domain.usecase.contentusecase + +import com.itlab.domain.model.ContentItem +import com.itlab.domain.repository.NotesRepository + +class GetContentItemUseCase( + private val notesRepository: NotesRepository, +) { + suspend operator fun invoke( + noteId: String, + itemId: String, + ): ContentItem? { + val note = + notesRepository.getNoteById(noteId) + ?: throw IllegalArgumentException("Note not found: $noteId") + + return note.contentItems.find { it.id == itemId } + } +} diff --git a/domain/src/main/java/com/itlab/domain/usecase/noteusecase/DuplicateNoteUseCase.kt b/domain/src/main/java/com/itlab/domain/usecase/noteusecase/DuplicateNoteUseCase.kt index 4225e5f..107b644 100644 --- a/domain/src/main/java/com/itlab/domain/usecase/noteusecase/DuplicateNoteUseCase.kt +++ b/domain/src/main/java/com/itlab/domain/usecase/noteusecase/DuplicateNoteUseCase.kt @@ -1,5 +1,6 @@ package com.itlab.domain.usecase.noteusecase +import com.itlab.domain.model.ContentItem import com.itlab.domain.repository.NotesRepository import kotlinx.datetime.Clock import java.util.UUID @@ -19,8 +20,16 @@ class DuplicateNoteUseCase( title = if (note.title.isBlank()) "Copy" else "${note.title} Copy", createdAt = now, updatedAt = now, + contentItems = + note.contentItems.map { item -> + when (item) { + is ContentItem.Text -> item.copy(id = UUID.randomUUID().toString()) + is ContentItem.Image -> item.copy(id = UUID.randomUUID().toString()) + is ContentItem.File -> item.copy(id = UUID.randomUUID().toString()) + is ContentItem.Link -> item.copy(id = UUID.randomUUID().toString()) + } + }, ) - return repo.createNote(duplicated) } } diff --git a/domain/src/test/java/com/itlab/domain/AIUseCasesTest.kt b/domain/src/test/java/com/itlab/domain/AIUseCasesTest.kt index 19e53af..0209b72 100644 --- a/domain/src/test/java/com/itlab/domain/AIUseCasesTest.kt +++ b/domain/src/test/java/com/itlab/domain/AIUseCasesTest.kt @@ -25,9 +25,7 @@ class AIUseCasesTest { override fun observeNotes(): Flow> = flow override fun observeNotesByFolder(folderId: String): Flow> = - flow.map { notes -> - notes.filter { it.folderId == folderId } - } + flow.map { notes -> notes.filter { it.folderId == folderId } } override suspend fun getNoteById(id: String): Note? = store[id] @@ -86,13 +84,14 @@ class AIUseCasesTest { title = "Test", contentItems = listOf( - ContentItem.Text("Hello"), + ContentItem.Text(text = "Hello"), ContentItem.Image( source = DataSource(localPath = "path/to/img"), mimeType = "image/png", ), ), ) + repo.createNote(note) val result = useCase("n1") @@ -129,8 +128,8 @@ class AIUseCasesTest { title = "Tags", contentItems = listOf( - ContentItem.Text("First line"), - ContentItem.Text("Second line"), + ContentItem.Text(text = "First line"), + ContentItem.Text(text = "Second line"), ContentItem.Image( source = DataSource(localPath = "/local/image.png"), mimeType = "image/png", @@ -139,18 +138,21 @@ class AIUseCasesTest { source = DataSource(remoteUrl = "https://example.com/image.jpg"), mimeType = "image/jpg", ), - ContentItem.Link("https://kotlinlang.org"), + ContentItem.Link(url = "https://kotlinlang.org"), ), ) + repo.createNote(note) val result = useCase("n2") assertEquals("First line\nSecond line", ai.textTagsInput) + assertEquals( listOf("/local/image.png", "https://example.com/image.jpg"), ai.imageTagsInput, ) + assertEquals( setOf("text-tag-1", "text-tag-2", "image-tag-1", "image-tag-2"), result, @@ -184,6 +186,7 @@ class AIUseCasesTest { title = "Summary", summary = "old summary", ) + repo.createNote(note) useCase("n3", "new summary") @@ -219,6 +222,7 @@ class AIUseCasesTest { title = "Tags", tags = setOf("old"), ) + repo.createNote(note) val newTags = setOf("kotlin", "android", "openvino") diff --git a/domain/src/test/java/com/itlab/domain/ContentItemUseCaseTest.kt b/domain/src/test/java/com/itlab/domain/ContentItemUseCaseTest.kt new file mode 100644 index 0000000..7e8957d --- /dev/null +++ b/domain/src/test/java/com/itlab/domain/ContentItemUseCaseTest.kt @@ -0,0 +1,148 @@ +package com.itlab.domain + +import com.itlab.domain.model.ContentItem +import com.itlab.domain.model.Note +import com.itlab.domain.repository.NotesRepository +import com.itlab.domain.usecase.contentusecase.AddContentItemUseCase +import com.itlab.domain.usecase.contentusecase.CreateContentItemUseCase +import com.itlab.domain.usecase.contentusecase.DeleteContentItemUseCase +import com.itlab.domain.usecase.contentusecase.GetContentItemUseCase +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.runBlocking +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNull +import org.junit.Test + +class ContentItemUseCaseTest { + private class FakeNotesRepo : NotesRepository { + private val store = mutableMapOf() + private val flow = MutableStateFlow>(emptyList()) + + override fun observeNotes() = flow + + override fun observeNotesByFolder(folderId: String) = flow + + override suspend fun getNoteById(id: String): Note? = store[id] + + override suspend fun createNote(note: Note): String { + store[note.id] = note + flow.value = store.values.toList() + return note.id + } + + override suspend fun updateNote(note: Note) { + store[note.id] = note + flow.value = store.values.toList() + } + + override suspend fun deleteNote(id: String) { + store.remove(id) + flow.value = store.values.toList() + } + } + + @Test + fun add_get_delete_content_item_flow() = + runBlocking { + val repo = FakeNotesRepo() + + val createItem = CreateContentItemUseCase() + val addItem = AddContentItemUseCase(repo) + val getItem = GetContentItemUseCase(repo) + val deleteItem = DeleteContentItemUseCase(repo) + + val note = Note(id = "n1", title = "Test") + repo.createNote(note) + + val item = + createItem( + ContentItem.Text( + text = "Hello", + ), + ) + + addItem("n1", item) + + val found = getItem("n1", item.id) + assertEquals("Hello", (found as ContentItem.Text).text) + + deleteItem("n1", item.id) + + val afterDelete = getItem("n1", item.id) + assertNull(afterDelete) + } + + @Test(expected = IllegalArgumentException::class) + fun addContentItem_without_id_throws() = + runBlocking { + val repo = FakeNotesRepo() + val addItem = AddContentItemUseCase(repo) + + val note = Note(id = "n1", title = "Test") + repo.createNote(note) + + val badItem = + ContentItem.Text( + id = "", + text = "Hello", + ) + + addItem("n1", badItem) + } + + @Test + fun add_multiple_content_items() = + runBlocking { + val repo = FakeNotesRepo() + val createItem = CreateContentItemUseCase() + val addItem = AddContentItemUseCase(repo) + val getItem = GetContentItemUseCase(repo) + + val note = Note(id = "n1", title = "Test") + repo.createNote(note) + + val item1 = createItem(ContentItem.Text(text = "A")) + val item2 = createItem(ContentItem.Text(text = "B")) + + addItem("n1", item1) + addItem("n1", item2) + + val found1 = getItem("n1", item1.id) + val found2 = getItem("n1", item2.id) + + assertEquals("A", (found1 as ContentItem.Text).text) + assertEquals("B", (found2 as ContentItem.Text).text) + } + + @Test + fun delete_non_existing_item_does_nothing() = + runBlocking { + val repo = FakeNotesRepo() + val deleteItem = DeleteContentItemUseCase(repo) + + val note = Note(id = "n1", title = "Test") + repo.createNote(note) + + deleteItem("n1", "wrong-id") // не должно упасть + + val result = repo.getNoteById("n1") + assertEquals(0, result?.contentItems?.size) + } + + @Test + fun content_item_does_not_affect_original_note_instance() = + runBlocking { + val repo = FakeNotesRepo() + val createItem = CreateContentItemUseCase() + val addItem = AddContentItemUseCase(repo) + + val note = Note(id = "n1", title = "Test") + repo.createNote(note) + + val item = createItem(ContentItem.Text(text = "Hello")) + + addItem("n1", item) + + assertEquals(0, note.contentItems.size) + } +} diff --git a/domain/src/test/java/com/itlab/domain/NoteTest.kt b/domain/src/test/java/com/itlab/domain/NoteTest.kt index 5d9e5e5..c90d6c8 100644 --- a/domain/src/test/java/com/itlab/domain/NoteTest.kt +++ b/domain/src/test/java/com/itlab/domain/NoteTest.kt @@ -30,15 +30,19 @@ class NoteTest { fun content_items_types() { val items = listOf( - ContentItem.Text("text"), + ContentItem.Text( + text = "text", + ), ContentItem.Image( source = DataSource(localPath = "/cache/images/pic_001.jpg"), - mimeType = "type", + mimeType = "image/png", + ), + ContentItem.Link( + url = "https://url.com", ), - ContentItem.Link("url"), ContentItem.File( source = DataSource(remoteUrl = "https://url.com"), - mimeType = "type", + mimeType = "application/pdf", name = "name", ), )