diff --git a/.idea/ChatHistory_schema_v2.xml b/.idea/ChatHistory_schema_v2.xml
index 3253196..b8bdf60 100644
--- a/.idea/ChatHistory_schema_v2.xml
+++ b/.idea/ChatHistory_schema_v2.xml
@@ -15,6 +15,7 @@
+
@@ -33,9 +34,11 @@
+
+
diff --git a/.idea/androidTestResultsUserPreferences.xml b/.idea/androidTestResultsUserPreferences.xml
index 51fb332..447cbf0 100644
--- a/.idea/androidTestResultsUserPreferences.xml
+++ b/.idea/androidTestResultsUserPreferences.xml
@@ -117,6 +117,7 @@
+
diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml
index 4ff54ea..7ae67ff 100644
--- a/.idea/deploymentTargetSelector.xml
+++ b/.idea/deploymentTargetSelector.xml
@@ -15,6 +15,17 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.pr_agent.toml b/.pr_agent.toml
index 2d6483f..f04dd14 100644
--- a/.pr_agent.toml
+++ b/.pr_agent.toml
@@ -1,6 +1,6 @@
[config]
model="openrouter/qwen/qwen-2.5-coder-32b-instruct:free"
-custom_model_max_tokens=9000
+custom_model_max_tokens=4000
[github_action_config]
auto_review = true
auto_describe = true
diff --git a/core/domain/src/main/java/com/core/domain/model/Note.kt b/core/domain/src/main/java/com/core/domain/model/Note.kt
index d7d4da5..f6f2855 100644
--- a/core/domain/src/main/java/com/core/domain/model/Note.kt
+++ b/core/domain/src/main/java/com/core/domain/model/Note.kt
@@ -8,4 +8,5 @@ data class Note(
val done: Boolean,
val date: String,
val time: String,
+ val optionRevealed: Boolean = false,
)
diff --git a/feature/tags/ui/src/androidTest/java/com/feature/tags/ui/screen/TagsViewModelTest.kt b/feature/tags/ui/src/androidTest/java/com/feature/tags/ui/screen/TagsViewModelTest.kt
index 4cf5633..3ad208b 100644
--- a/feature/tags/ui/src/androidTest/java/com/feature/tags/ui/screen/TagsViewModelTest.kt
+++ b/feature/tags/ui/src/androidTest/java/com/feature/tags/ui/screen/TagsViewModelTest.kt
@@ -4,6 +4,7 @@ import androidx.lifecycle.SavedStateHandle
import app.cash.turbine.test
import com.core.domain.model.Note
import com.core.domain.model.TagWithNotes
+import com.core.domain.usecase.UpdateNoteDeletedUseCase
import com.core.domain.usecase.UpdateNoteDoneUseCase
import com.feature.tags.domain.usecase.GetTagWithNotesUseCase
import com.feature.tags.domain.usecase.UpdateTagNameUseCase
@@ -33,6 +34,7 @@ class TagsViewModelTest {
private lateinit var getTagWithNotesUseCase: GetTagWithNotesUseCase
private lateinit var updateTagNameUseCase: UpdateTagNameUseCase
private lateinit var updateNoteDoneUseCase: UpdateNoteDoneUseCase
+ private lateinit var updateNoteDeletedUseCase: UpdateNoteDeletedUseCase
private lateinit var tagsViewModel: TagsViewModel
private val testDispatcher = StandardTestDispatcher()
@@ -70,6 +72,7 @@ class TagsViewModelTest {
getTagWithNotesUseCase = mockk()
updateTagNameUseCase = mockk()
updateNoteDoneUseCase = mockk()
+ updateNoteDeletedUseCase = mockk()
}
@Test
@@ -84,8 +87,9 @@ class TagsViewModelTest {
TagsViewModel(
savedStateHandle = savedStateHandle,
getTagWithNotesUseCase = getTagWithNotesUseCase,
- updateTagNameUseCase = updateTagNameUseCase,
- updateNoteDoneUseCase = updateNoteDoneUseCase,
+ updateTagNameUseCase = { updateTagNameUseCase },
+ updateNoteDoneUseCase = { updateNoteDoneUseCase },
+ updateNoteDeletedUseCase = { updateNoteDeletedUseCase },
)
// Assert
@@ -109,8 +113,9 @@ class TagsViewModelTest {
TagsViewModel(
savedStateHandle = savedStateHandle,
getTagWithNotesUseCase = getTagWithNotesUseCase,
- updateTagNameUseCase = updateTagNameUseCase,
- updateNoteDoneUseCase = updateNoteDoneUseCase,
+ updateTagNameUseCase = { updateTagNameUseCase },
+ updateNoteDoneUseCase = { updateNoteDoneUseCase },
+ updateNoteDeletedUseCase = { updateNoteDeletedUseCase },
)
// Assert
@@ -133,8 +138,9 @@ class TagsViewModelTest {
TagsViewModel(
savedStateHandle = savedStateHandle,
getTagWithNotesUseCase = getTagWithNotesUseCase,
- updateTagNameUseCase = updateTagNameUseCase,
- updateNoteDoneUseCase = updateNoteDoneUseCase,
+ updateTagNameUseCase = { updateTagNameUseCase },
+ updateNoteDoneUseCase = { updateNoteDoneUseCase },
+ updateNoteDeletedUseCase = { updateNoteDeletedUseCase },
)
// Act & Assert
@@ -161,8 +167,9 @@ class TagsViewModelTest {
TagsViewModel(
savedStateHandle = savedStateHandle,
getTagWithNotesUseCase = getTagWithNotesUseCase,
- updateTagNameUseCase = updateTagNameUseCase,
- updateNoteDoneUseCase = updateNoteDoneUseCase,
+ updateTagNameUseCase = { updateTagNameUseCase },
+ updateNoteDoneUseCase = { updateNoteDoneUseCase },
+ updateNoteDeletedUseCase = { updateNoteDeletedUseCase },
)
// Assert
@@ -185,7 +192,7 @@ class TagsViewModelTest {
}
@Test
- fun markNoteAsDone_shouldMarkANoteAsDone() =
+ fun markNoteAsDone_shouldMarkNoteAsDone() =
runTest {
// Arrange
val note =
@@ -207,8 +214,9 @@ class TagsViewModelTest {
TagsViewModel(
savedStateHandle = savedStateHandle,
getTagWithNotesUseCase = getTagWithNotesUseCase,
- updateTagNameUseCase = updateTagNameUseCase,
- updateNoteDoneUseCase = updateNoteDoneUseCase,
+ updateTagNameUseCase = { updateTagNameUseCase },
+ updateNoteDoneUseCase = { updateNoteDoneUseCase },
+ updateNoteDeletedUseCase = { updateNoteDeletedUseCase },
)
// Assert
@@ -223,6 +231,46 @@ class TagsViewModelTest {
}
}
+ @Test
+ fun markNoteAsDeleted_shouldMarkNoteAsDeleted() =
+ runTest {
+ // Arrange
+ val note =
+ Note(
+ id = 1L,
+ content = "Test note 1",
+ timestamp = 123456789,
+ tagId = 1L,
+ done = false,
+ date = "2025-06-25",
+ time = "00:00:00",
+ )
+ every { getTagWithNotesUseCase(any()) } returns flowOf(tagWithNotes)
+ savedStateHandle = SavedStateHandle(mapOf("tagId" to 1L))
+ coEvery { updateNoteDeletedUseCase(any(), any()) } returns 1
+
+ // Act
+ tagsViewModel =
+ TagsViewModel(
+ savedStateHandle = savedStateHandle,
+ getTagWithNotesUseCase = getTagWithNotesUseCase,
+ updateTagNameUseCase = { updateTagNameUseCase },
+ updateNoteDoneUseCase = { updateNoteDoneUseCase },
+ updateNoteDeletedUseCase = { updateNoteDeletedUseCase },
+ )
+
+ // Assert
+ tagsViewModel.tagsUiState.test {
+ assertEquals(TagsUiState.Idle, awaitItem())
+ assertEquals(TagsUiState.Loading, awaitItem())
+ assertEquals(TagsUiState.TagLoaded(tagWithNotes), awaitItem())
+ tagsViewModel.markNoteAsDeleted(note = note)
+ advanceUntilIdle()
+ coVerify { updateNoteDeletedUseCase(note.id, true) }
+ cancelAndIgnoreRemainingEvents()
+ }
+ }
+
@After
fun tearDown() {
Dispatchers.resetMain()
diff --git a/feature/tags/ui/src/main/java/com/feature/tags/ui/navigation/InternalTagsFeatureApi.kt b/feature/tags/ui/src/main/java/com/feature/tags/ui/navigation/InternalTagsFeatureApi.kt
index ae3c373..0ba3b7d 100644
--- a/feature/tags/ui/src/main/java/com/feature/tags/ui/navigation/InternalTagsFeatureApi.kt
+++ b/feature/tags/ui/src/main/java/com/feature/tags/ui/navigation/InternalTagsFeatureApi.kt
@@ -76,6 +76,7 @@ internal class InternalTagsFeatureApi
navHostController.navigate(AddEditNoteScreen(noteId = note.id))
},
onNoteDoneClick = tagsViewModel::markNoteAsDone,
+ onNoteDeleteClick = tagsViewModel::markNoteAsDeleted,
)
}
}
diff --git a/feature/tags/ui/src/main/java/com/feature/tags/ui/screen/TagScreenUi.kt b/feature/tags/ui/src/main/java/com/feature/tags/ui/screen/TagScreenUi.kt
index 684e91c..53e80ec 100644
--- a/feature/tags/ui/src/main/java/com/feature/tags/ui/screen/TagScreenUi.kt
+++ b/feature/tags/ui/src/main/java/com/feature/tags/ui/screen/TagScreenUi.kt
@@ -25,6 +25,7 @@ fun TagScreenUi(
onSaveTagNameClick: (Long, String) -> Unit,
onNoteClick: (Note) -> Unit,
onNoteDoneClick: (Note) -> Unit,
+ onNoteDeleteClick: (Note) -> Unit,
modifier: Modifier = Modifier,
) {
val state = tagsUiState
@@ -62,6 +63,7 @@ fun TagScreenUi(
onNoteClick = onNoteClick,
onEditTagClick = onEditTagClick,
onNoteDoneClick = onNoteDoneClick,
+ onNoteDeleteClick = onNoteDeleteClick,
)
if (state.tagsUiBottomSheet is TagsUiBottomSheet.RenameTagBottomSheet) {
@@ -93,6 +95,7 @@ private fun TagScreenPreview(
hideEditTagBottomSheet = {},
onNoteClick = {},
onNoteDoneClick = {},
+ onNoteDeleteClick = {},
)
}
}
diff --git a/feature/tags/ui/src/main/java/com/feature/tags/ui/screen/TagsViewModel.kt b/feature/tags/ui/src/main/java/com/feature/tags/ui/screen/TagsViewModel.kt
index 621f163..660a6f6 100644
--- a/feature/tags/ui/src/main/java/com/feature/tags/ui/screen/TagsViewModel.kt
+++ b/feature/tags/ui/src/main/java/com/feature/tags/ui/screen/TagsViewModel.kt
@@ -9,9 +9,11 @@ import androidx.lifecycle.viewModelScope
import androidx.navigation.toRoute
import com.core.common.navigation.TagScreen
import com.core.domain.model.Note
+import com.core.domain.usecase.UpdateNoteDeletedUseCase
import com.core.domain.usecase.UpdateNoteDoneUseCase
import com.feature.tags.domain.usecase.GetTagWithNotesUseCase
import com.feature.tags.domain.usecase.UpdateTagNameUseCase
+import dagger.Lazy
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
@@ -26,8 +28,9 @@ class TagsViewModel
constructor(
@Assisted private val savedStateHandle: SavedStateHandle,
private val getTagWithNotesUseCase: GetTagWithNotesUseCase,
- private val updateTagNameUseCase: UpdateTagNameUseCase,
- private val updateNoteDoneUseCase: UpdateNoteDoneUseCase,
+ private val updateTagNameUseCase: Lazy,
+ private val updateNoteDoneUseCase: Lazy,
+ private val updateNoteDeletedUseCase: Lazy,
) : ViewModel() {
companion object {
private val TAG = TagsViewModel::class.simpleName
@@ -65,7 +68,7 @@ class TagsViewModel
@Suppress("TooGenericExceptionCaught")
viewModelScope.launch {
try {
- updateTagNameUseCase(tagId = tagId, newName = newName)
+ updateTagNameUseCase.get()(tagId = tagId, newName = newName)
} catch (ex: Exception) {
Log.e(TAG, "Error updating tag name: ${ex.message}", ex)
}
@@ -84,7 +87,13 @@ class TagsViewModel
fun markNoteAsDone(note: Note) {
viewModelScope.launch {
- updateNoteDoneUseCase(id = note.id, done = true)
+ updateNoteDoneUseCase.get()(id = note.id, done = true)
+ }
+ }
+
+ fun markNoteAsDeleted(note: Note) {
+ viewModelScope.launch {
+ updateNoteDeletedUseCase.get()(id = note.id, deleted = true)
}
}
}
diff --git a/feature/tags/ui/src/main/java/com/feature/tags/ui/screen/composables/TagContent.kt b/feature/tags/ui/src/main/java/com/feature/tags/ui/screen/composables/TagContent.kt
index 711b813..d6f8dfd 100644
--- a/feature/tags/ui/src/main/java/com/feature/tags/ui/screen/composables/TagContent.kt
+++ b/feature/tags/ui/src/main/java/com/feature/tags/ui/screen/composables/TagContent.kt
@@ -5,6 +5,7 @@ import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
@@ -18,14 +19,19 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.core.common.theme.LightGray
+import com.core.common.theme.Red
import com.core.common.theme.TaskerTheme
+import com.core.common.ui.ActionIcon
+import com.core.common.ui.SwipeableItemWithActions
import com.core.common.utils.toColorSafely
import com.core.domain.model.Note
import com.core.domain.model.TagWithNotes
@@ -39,6 +45,7 @@ fun TagContent(
onNoteClick: (Note) -> Unit,
onEditTagClick: (TagWithNotes) -> Unit,
onNoteDoneClick: (Note) -> Unit,
+ onNoteDeleteClick: (Note) -> Unit,
modifier: Modifier = Modifier,
) {
Box(modifier = modifier) {
@@ -96,12 +103,27 @@ fun TagContent(
.fillMaxSize(),
) {
items(tagsUiState.tag.notes, key = { it.id }) { note ->
- TagNoteItem(
- modifier = Modifier.fillMaxWidth(),
- note = note,
- onNoteClick = onNoteClick,
- onNoteDoneClick = onNoteDoneClick,
- )
+
+ SwipeableItemWithActions(
+ modifier = Modifier.animateItem(),
+ isRevealed = note.optionRevealed,
+ actions = {
+ ActionIcon(
+ onClick = { onNoteDeleteClick(note) },
+ backgroundColor = Red,
+ icon = ImageVector.vectorResource(id = com.core.common.R.drawable.ic_delete),
+ modifier = Modifier.fillMaxHeight(),
+ contentDescription = "Delete Icon",
+ )
+ },
+ ) {
+ TagNoteItem(
+ modifier = Modifier.fillMaxWidth().background(tagsUiState.tag.color.toColorSafely()),
+ note = note,
+ onNoteClick = onNoteClick,
+ onNoteDoneClick = onNoteDoneClick,
+ )
+ }
HorizontalDivider(
modifier = Modifier.padding(start = 60.dp),
color = Color.White,
@@ -119,10 +141,15 @@ private fun TagContentPreview() {
TaskerTheme {
TagContent(
modifier = Modifier.fillMaxSize(),
- tagsUiState = TagsUiState.TagLoaded(tag = tagWithNotes, tagsUiBottomSheet = TagsUiBottomSheet.None),
+ tagsUiState =
+ TagsUiState.TagLoaded(
+ tag = tagWithNotes,
+ tagsUiBottomSheet = TagsUiBottomSheet.None,
+ ),
onEditTagClick = {},
onNoteClick = {},
onNoteDoneClick = {},
+ onNoteDeleteClick = {},
)
}
}