mirror of
https://github.com/chatmail/core.git
synced 2026-05-16 21:36:30 +03:00
api: allow to filter by unread in chatlist:try_load (#4824)
close #4738
This commit is contained in:
@@ -884,7 +884,8 @@ int dc_preconfigure_keypair (dc_context_t* context, const cha
|
|||||||
* - if the flag DC_GCL_ADD_ALLDONE_HINT is set, DC_CHAT_ID_ALLDONE_HINT
|
* - if the flag DC_GCL_ADD_ALLDONE_HINT is set, DC_CHAT_ID_ALLDONE_HINT
|
||||||
* is added as needed.
|
* is added as needed.
|
||||||
* @param query_str An optional query for filtering the list. Only chats matching this query
|
* @param query_str An optional query for filtering the list. Only chats matching this query
|
||||||
* are returned. Give NULL for no filtering.
|
* are returned. Give NULL for no filtering. When `is:unread` is contained in the query,
|
||||||
|
* the chatlist is filtered such that only chats with unread messages show up.
|
||||||
* @param query_id An optional contact ID for filtering the list. Only chats including this contact ID
|
* @param query_id An optional contact ID for filtering the list. Only chats including this contact ID
|
||||||
* are returned. Give 0 for no filtering.
|
* are returned. Give 0 for no filtering.
|
||||||
* @return A chatlist as an dc_chatlist_t object.
|
* @return A chatlist as an dc_chatlist_t object.
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
//! # Chat list module.
|
//! # Chat list module.
|
||||||
|
|
||||||
use anyhow::{ensure, Context as _, Result};
|
use anyhow::{ensure, Context as _, Result};
|
||||||
|
use once_cell::sync::Lazy;
|
||||||
|
|
||||||
use crate::chat::{update_special_chat_names, Chat, ChatId, ChatVisibility};
|
use crate::chat::{update_special_chat_names, Chat, ChatId, ChatVisibility};
|
||||||
use crate::constants::{
|
use crate::constants::{
|
||||||
@@ -15,6 +16,10 @@ use crate::stock_str;
|
|||||||
use crate::summary::Summary;
|
use crate::summary::Summary;
|
||||||
use crate::tools::IsNoneOrEmpty;
|
use crate::tools::IsNoneOrEmpty;
|
||||||
|
|
||||||
|
/// Regex to find out if a query should filter by unread messages.
|
||||||
|
pub static IS_UNREAD_FILTER: Lazy<regex::Regex> =
|
||||||
|
Lazy::new(|| regex::Regex::new(r"\bis:unread\b").unwrap());
|
||||||
|
|
||||||
/// An object representing a single chatlist in memory.
|
/// An object representing a single chatlist in memory.
|
||||||
///
|
///
|
||||||
/// Chatlist objects contain chat IDs and, if possible, message IDs belonging to them.
|
/// Chatlist objects contain chat IDs and, if possible, message IDs belonging to them.
|
||||||
@@ -78,7 +83,8 @@ impl Chatlist {
|
|||||||
/// - if the flag DC_GCL_ADD_ALLDONE_HINT is set, DC_CHAT_ID_ALLDONE_HINT
|
/// - if the flag DC_GCL_ADD_ALLDONE_HINT is set, DC_CHAT_ID_ALLDONE_HINT
|
||||||
/// is added as needed.
|
/// is added as needed.
|
||||||
/// `query`: An optional query for filtering the list. Only chats matching this query
|
/// `query`: An optional query for filtering the list. Only chats matching this query
|
||||||
/// are returned.
|
/// are returned. When `is:unread` is contained in the query, the chatlist is
|
||||||
|
/// filtered such that only chats with unread messages show up.
|
||||||
/// `query_contact_id`: An optional contact ID for filtering the list. Only chats including this contact ID
|
/// `query_contact_id`: An optional contact ID for filtering the list. Only chats including this contact ID
|
||||||
/// are returned.
|
/// are returned.
|
||||||
pub async fn try_load(
|
pub async fn try_load(
|
||||||
@@ -172,8 +178,10 @@ impl Chatlist {
|
|||||||
)
|
)
|
||||||
.await?
|
.await?
|
||||||
} else if let Some(query) = query {
|
} else if let Some(query) = query {
|
||||||
let query = query.trim().to_string();
|
let mut query = query.trim().to_string();
|
||||||
ensure!(!query.is_empty(), "missing query");
|
ensure!(!query.is_empty(), "query mustn't be empty");
|
||||||
|
let only_unread = IS_UNREAD_FILTER.find(&query).is_some();
|
||||||
|
query = IS_UNREAD_FILTER.replace(&query, "").trim().to_string();
|
||||||
|
|
||||||
// allow searching over special names that may change at any time
|
// allow searching over special names that may change at any time
|
||||||
// when the ui calls set_stock_translation()
|
// when the ui calls set_stock_translation()
|
||||||
@@ -198,9 +206,10 @@ impl Chatlist {
|
|||||||
WHERE c.id>9 AND c.id!=?2
|
WHERE c.id>9 AND c.id!=?2
|
||||||
AND c.blocked!=1
|
AND c.blocked!=1
|
||||||
AND c.name LIKE ?3
|
AND c.name LIKE ?3
|
||||||
|
AND (NOT ?4 OR EXISTS (SELECT 1 FROM msgs m WHERE m.chat_id = c.id AND m.state == ?5 AND hidden=0))
|
||||||
GROUP BY c.id
|
GROUP BY c.id
|
||||||
ORDER BY IFNULL(m.timestamp,c.created_timestamp) DESC, m.id DESC;",
|
ORDER BY IFNULL(m.timestamp,c.created_timestamp) DESC, m.id DESC;",
|
||||||
(MessageState::OutDraft, skip_id, str_like_cmd),
|
(MessageState::OutDraft, skip_id, str_like_cmd, only_unread, MessageState::InFresh),
|
||||||
process_row,
|
process_row,
|
||||||
process_rows,
|
process_rows,
|
||||||
)
|
)
|
||||||
@@ -462,7 +471,8 @@ pub async fn get_last_message_for_chat(
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::chat::{
|
use crate::chat::{
|
||||||
create_group_chat, get_chat_contacts, remove_contact_from_chat, ProtectionStatus,
|
add_contact_to_chat, create_group_chat, get_chat_contacts, remove_contact_from_chat,
|
||||||
|
send_text_msg, ProtectionStatus,
|
||||||
};
|
};
|
||||||
use crate::message::Viewtype;
|
use crate::message::Viewtype;
|
||||||
use crate::receive_imf::receive_imf;
|
use crate::receive_imf::receive_imf;
|
||||||
@@ -471,7 +481,7 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||||
async fn test_try_load() {
|
async fn test_try_load() {
|
||||||
let t = TestContext::new().await;
|
let t = TestContext::new_bob().await;
|
||||||
let chat_id1 = create_group_chat(&t, ProtectionStatus::Unprotected, "a chat")
|
let chat_id1 = create_group_chat(&t, ProtectionStatus::Unprotected, "a chat")
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@@ -510,6 +520,31 @@ mod tests {
|
|||||||
let chats = Chatlist::try_load(&t, 0, Some("b"), None).await.unwrap();
|
let chats = Chatlist::try_load(&t, 0, Some("b"), None).await.unwrap();
|
||||||
assert_eq!(chats.len(), 1);
|
assert_eq!(chats.len(), 1);
|
||||||
|
|
||||||
|
// receive a message from alice
|
||||||
|
let alice = TestContext::new_alice().await;
|
||||||
|
let alice_chat_id = create_group_chat(&alice, ProtectionStatus::Unprotected, "alice chat")
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
add_contact_to_chat(
|
||||||
|
&alice,
|
||||||
|
alice_chat_id,
|
||||||
|
Contact::create(&alice, "bob", "bob@example.net")
|
||||||
|
.await
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
send_text_msg(&alice, alice_chat_id, "hi".into())
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
let sent_msg = alice.pop_sent_msg().await;
|
||||||
|
|
||||||
|
t.recv_msg(&sent_msg).await;
|
||||||
|
let chats = Chatlist::try_load(&t, 0, Some("is:unread"), None)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
assert!(chats.len() == 1);
|
||||||
|
|
||||||
let chats = Chatlist::try_load(&t, DC_GCL_ARCHIVED_ONLY, None, None)
|
let chats = Chatlist::try_load(&t, DC_GCL_ARCHIVED_ONLY, None, None)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|||||||
Reference in New Issue
Block a user