feat: Add PENDING_DELETE filter to all paginated queries and implement accordion-style drawer navigation
- Add sync_status != 'PENDING_DELETE' condition to all PagingSource queries in LinkDao (getAllLinksPaged, searchLinks, searchLinksFullText, getLinksByTag, getLinksByMultipleTags, getLinksInCollectionPaged, getDeadLinks, getPinnedLinksPaged) - Update LinkRepositoryImpl to exclude PENDING_DELETE items in dynamic query builder and multi-tag filtering - Replace independent drawer accordion states
This commit is contained in:
parent
b9efb14b8d
commit
e742502bdc
@ -25,7 +25,7 @@ interface LinkDao {
|
|||||||
@Query("SELECT * FROM links ORDER BY is_pinned DESC, created_at DESC")
|
@Query("SELECT * FROM links ORDER BY is_pinned DESC, created_at DESC")
|
||||||
fun getAllLinks(): Flow<List<LinkEntity>>
|
fun getAllLinks(): Flow<List<LinkEntity>>
|
||||||
|
|
||||||
@Query("SELECT * FROM links ORDER BY is_pinned DESC, created_at DESC")
|
@Query("SELECT * FROM links WHERE sync_status != 'PENDING_DELETE' ORDER BY is_pinned DESC, created_at DESC")
|
||||||
fun getAllLinksPaged(): PagingSource<Int, LinkEntity>
|
fun getAllLinksPaged(): PagingSource<Int, LinkEntity>
|
||||||
|
|
||||||
@Query("SELECT * FROM links WHERE id = :id")
|
@Query("SELECT * FROM links WHERE id = :id")
|
||||||
@ -41,9 +41,10 @@ interface LinkDao {
|
|||||||
|
|
||||||
@Query("""
|
@Query("""
|
||||||
SELECT * FROM links
|
SELECT * FROM links
|
||||||
WHERE title LIKE '%' || :query || '%'
|
WHERE sync_status != 'PENDING_DELETE'
|
||||||
|
AND (title LIKE '%' || :query || '%'
|
||||||
OR description LIKE '%' || :query || '%'
|
OR description LIKE '%' || :query || '%'
|
||||||
OR url LIKE '%' || :query || '%'
|
OR url LIKE '%' || :query || '%')
|
||||||
ORDER BY is_pinned DESC, created_at DESC
|
ORDER BY is_pinned DESC, created_at DESC
|
||||||
""")
|
""")
|
||||||
fun searchLinks(query: String): PagingSource<Int, LinkEntity>
|
fun searchLinks(query: String): PagingSource<Int, LinkEntity>
|
||||||
@ -52,6 +53,7 @@ interface LinkDao {
|
|||||||
SELECT links.* FROM links
|
SELECT links.* FROM links
|
||||||
INNER JOIN links_fts ON links.id = links_fts.rowid
|
INNER JOIN links_fts ON links.id = links_fts.rowid
|
||||||
WHERE links_fts MATCH :query
|
WHERE links_fts MATCH :query
|
||||||
|
AND links.sync_status != 'PENDING_DELETE'
|
||||||
ORDER BY links.is_pinned DESC, links.created_at DESC
|
ORDER BY links.is_pinned DESC, links.created_at DESC
|
||||||
""")
|
""")
|
||||||
fun searchLinksFullText(query: String): PagingSource<Int, LinkEntity>
|
fun searchLinksFullText(query: String): PagingSource<Int, LinkEntity>
|
||||||
@ -59,6 +61,7 @@ interface LinkDao {
|
|||||||
@Query("""
|
@Query("""
|
||||||
SELECT * FROM links
|
SELECT * FROM links
|
||||||
WHERE tags LIKE '%' || :tag || '%'
|
WHERE tags LIKE '%' || :tag || '%'
|
||||||
|
AND sync_status != 'PENDING_DELETE'
|
||||||
ORDER BY is_pinned DESC, created_at DESC
|
ORDER BY is_pinned DESC, created_at DESC
|
||||||
""")
|
""")
|
||||||
fun getLinksByTag(tag: String): PagingSource<Int, LinkEntity>
|
fun getLinksByTag(tag: String): PagingSource<Int, LinkEntity>
|
||||||
@ -66,6 +69,7 @@ interface LinkDao {
|
|||||||
@Query("""
|
@Query("""
|
||||||
SELECT * FROM links
|
SELECT * FROM links
|
||||||
WHERE tags LIKE '%' || :tag1 || '%' AND tags LIKE '%' || :tag2 || '%'
|
WHERE tags LIKE '%' || :tag1 || '%' AND tags LIKE '%' || :tag2 || '%'
|
||||||
|
AND sync_status != 'PENDING_DELETE'
|
||||||
ORDER BY is_pinned DESC, created_at DESC
|
ORDER BY is_pinned DESC, created_at DESC
|
||||||
""")
|
""")
|
||||||
fun getLinksByMultipleTags(tag1: String, tag2: String): PagingSource<Int, LinkEntity>
|
fun getLinksByMultipleTags(tag1: String, tag2: String): PagingSource<Int, LinkEntity>
|
||||||
@ -80,6 +84,7 @@ interface LinkDao {
|
|||||||
SELECT links.* FROM links
|
SELECT links.* FROM links
|
||||||
INNER JOIN collection_links ON links.id = collection_links.link_id
|
INNER JOIN collection_links ON links.id = collection_links.link_id
|
||||||
WHERE collection_links.collection_id = :collectionId
|
WHERE collection_links.collection_id = :collectionId
|
||||||
|
AND links.sync_status != 'PENDING_DELETE'
|
||||||
ORDER BY links.is_pinned DESC, collection_links.added_at DESC
|
ORDER BY links.is_pinned DESC, collection_links.added_at DESC
|
||||||
""")
|
""")
|
||||||
fun getLinksInCollectionPaged(collectionId: Long): PagingSource<Int, LinkEntity>
|
fun getLinksInCollectionPaged(collectionId: Long): PagingSource<Int, LinkEntity>
|
||||||
@ -103,6 +108,7 @@ interface LinkDao {
|
|||||||
@Query("""
|
@Query("""
|
||||||
SELECT * FROM links
|
SELECT * FROM links
|
||||||
WHERE link_check_status = 'BROKEN'
|
WHERE link_check_status = 'BROKEN'
|
||||||
|
AND sync_status != 'PENDING_DELETE'
|
||||||
ORDER BY last_health_check DESC
|
ORDER BY last_health_check DESC
|
||||||
""")
|
""")
|
||||||
fun getDeadLinks(): PagingSource<Int, LinkEntity>
|
fun getDeadLinks(): PagingSource<Int, LinkEntity>
|
||||||
@ -152,7 +158,7 @@ interface LinkDao {
|
|||||||
@Query("SELECT * FROM links WHERE is_pinned = 1 ORDER BY created_at DESC")
|
@Query("SELECT * FROM links WHERE is_pinned = 1 ORDER BY created_at DESC")
|
||||||
fun getPinnedLinks(): Flow<List<LinkEntity>>
|
fun getPinnedLinks(): Flow<List<LinkEntity>>
|
||||||
|
|
||||||
@Query("SELECT * FROM links WHERE is_pinned = 1 ORDER BY created_at DESC")
|
@Query("SELECT * FROM links WHERE is_pinned = 1 AND sync_status != 'PENDING_DELETE' ORDER BY created_at DESC")
|
||||||
fun getPinnedLinksPaged(): PagingSource<Int, LinkEntity>
|
fun getPinnedLinksPaged(): PagingSource<Int, LinkEntity>
|
||||||
|
|
||||||
// ====== Sync ======
|
// ====== Sync ======
|
||||||
|
|||||||
@ -79,7 +79,7 @@ constructor(
|
|||||||
} else {
|
} else {
|
||||||
val whereClause = tags.joinToString(" AND ") { "tags LIKE ?" }
|
val whereClause = tags.joinToString(" AND ") { "tags LIKE ?" }
|
||||||
val sql =
|
val sql =
|
||||||
"SELECT * FROM links WHERE $whereClause ORDER BY is_pinned DESC, created_at DESC"
|
"SELECT * FROM links WHERE sync_status != 'PENDING_DELETE' AND $whereClause ORDER BY is_pinned DESC, created_at DESC"
|
||||||
val args: Array<Any> = tags.map { "%\"$it\"%" }.toTypedArray()
|
val args: Array<Any> = tags.map { "%\"$it\"%" }.toTypedArray()
|
||||||
linkDao.getLinksByTags(SimpleSQLiteQuery(sql, args))
|
linkDao.getLinksByTags(SimpleSQLiteQuery(sql, args))
|
||||||
}
|
}
|
||||||
@ -420,7 +420,7 @@ constructor(
|
|||||||
// ====== Helpers ======
|
// ====== Helpers ======
|
||||||
|
|
||||||
private fun buildFilteredQuery(filter: com.shaarit.domain.model.BookmarkFilter): PagingSource<Int, LinkEntity> {
|
private fun buildFilteredQuery(filter: com.shaarit.domain.model.BookmarkFilter): PagingSource<Int, LinkEntity> {
|
||||||
val conditions = mutableListOf<String>()
|
val conditions = mutableListOf<String>("sync_status != 'PENDING_DELETE'")
|
||||||
val args = mutableListOf<Any>()
|
val args = mutableListOf<Any>()
|
||||||
|
|
||||||
// Time-based filters
|
// Time-based filters
|
||||||
|
|||||||
@ -318,10 +318,8 @@ fun FeedScreen(
|
|||||||
val reminderViewModel: com.shaarit.presentation.reminders.ReminderViewModel = hiltViewModel()
|
val reminderViewModel: com.shaarit.presentation.reminders.ReminderViewModel = hiltViewModel()
|
||||||
val linkIdsWithReminders by reminderViewModel.linkIdsWithReminders.collectAsState()
|
val linkIdsWithReminders by reminderViewModel.linkIdsWithReminders.collectAsState()
|
||||||
|
|
||||||
// États des accordéons du drawer
|
// États des accordéons du drawer (accordion: un seul ouvert à la fois)
|
||||||
var mainMenuExpanded by remember { mutableStateOf(true) }
|
var expandedSection by remember { mutableStateOf("main") }
|
||||||
var collectionsExpanded by remember { mutableStateOf(true) }
|
|
||||||
var tagsExpanded by remember { mutableStateOf(true) }
|
|
||||||
|
|
||||||
// Set initial tag filter
|
// Set initial tag filter
|
||||||
LaunchedEffect(initialTagFilter) { viewModel.setInitialTagFilter(initialTagFilter) }
|
LaunchedEffect(initialTagFilter) { viewModel.setInitialTagFilter(initialTagFilter) }
|
||||||
@ -404,8 +402,8 @@ fun FeedScreen(
|
|||||||
// Navigation principale - Accordéon
|
// Navigation principale - Accordéon
|
||||||
AccordionSection(
|
AccordionSection(
|
||||||
title = "MENU PRINCIPAL",
|
title = "MENU PRINCIPAL",
|
||||||
expanded = mainMenuExpanded,
|
expanded = expandedSection == "main",
|
||||||
onToggle = { mainMenuExpanded = !mainMenuExpanded },
|
onToggle = { expandedSection = if (expandedSection == "main") "" else "main" },
|
||||||
modifier = Modifier.padding(top = 8.dp)
|
modifier = Modifier.padding(top = 8.dp)
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
@ -493,8 +491,8 @@ fun FeedScreen(
|
|||||||
// Types de contenu - Accordéon
|
// Types de contenu - Accordéon
|
||||||
AccordionSection(
|
AccordionSection(
|
||||||
title = "TYPES DE CONTENU",
|
title = "TYPES DE CONTENU",
|
||||||
expanded = true,
|
expanded = expandedSection == "content",
|
||||||
onToggle = { },
|
onToggle = { expandedSection = if (expandedSection == "content") "" else "content" },
|
||||||
modifier = Modifier.padding(vertical = 4.dp)
|
modifier = Modifier.padding(vertical = 4.dp)
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
@ -633,8 +631,8 @@ fun FeedScreen(
|
|||||||
// Collections rapides - Accordéon
|
// Collections rapides - Accordéon
|
||||||
AccordionSection(
|
AccordionSection(
|
||||||
title = "COLLECTIONS",
|
title = "COLLECTIONS",
|
||||||
expanded = collectionsExpanded,
|
expanded = expandedSection == "collections",
|
||||||
onToggle = { collectionsExpanded = !collectionsExpanded },
|
onToggle = { expandedSection = if (expandedSection == "collections") "" else "collections" },
|
||||||
trailingContent = {
|
trailingContent = {
|
||||||
TextButton(
|
TextButton(
|
||||||
onClick = {
|
onClick = {
|
||||||
@ -699,8 +697,8 @@ fun FeedScreen(
|
|||||||
// Tags populaires - Accordéon
|
// Tags populaires - Accordéon
|
||||||
AccordionSection(
|
AccordionSection(
|
||||||
title = "TAGS POPULAIRES",
|
title = "TAGS POPULAIRES",
|
||||||
expanded = tagsExpanded,
|
expanded = expandedSection == "tags",
|
||||||
onToggle = { tagsExpanded = !tagsExpanded },
|
onToggle = { expandedSection = if (expandedSection == "tags") "" else "tags" },
|
||||||
trailingContent = {
|
trailingContent = {
|
||||||
TextButton(
|
TextButton(
|
||||||
onClick = {
|
onClick = {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
<#
|
<#
|
||||||
.SYNOPSIS
|
.SYNOPSIS
|
||||||
Script de build et de versioning pour ShaarIt.
|
Script de build et de versioning pour ShaarIt.
|
||||||
.DESCRIPTION
|
.DESCRIPTION
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
#Thu Feb 12 09:29:54 2026
|
#Thu Feb 12 10:28:52 2026
|
||||||
VERSION_NAME=1.2.0
|
VERSION_NAME=1.2.3
|
||||||
VERSION_CODE=8
|
VERSION_CODE=11
|
||||||
Loading…
x
Reference in New Issue
Block a user