feat: Add strings 'You left the channel.' and 'Scan to join Channel' (#7266)

Close https://github.com/chatmail/core/issues/7233

Part of https://github.com/chatmail/core/issues/6884
This commit is contained in:
Hocuri
2025-10-02 16:57:24 +02:00
committed by GitHub
parent d509b0cf5c
commit 9ec0332483
6 changed files with 46 additions and 18 deletions

View File

@@ -4207,7 +4207,7 @@ pub async fn remove_contact_from_chat(
if chat.typ == Chattype::Group && chat.is_promoted() {
let addr = contact.get_addr();
let res = send_member_removal_msg(context, chat_id, contact_id, addr).await;
let res = send_member_removal_msg(context, &chat, contact_id, addr).await;
if contact_id == ContactId::SELF {
res?;
@@ -4231,7 +4231,7 @@ pub async fn remove_contact_from_chat(
// For incoming broadcast channels, it's not possible to remove members,
// but it's possible to leave:
let self_addr = context.get_primary_self_addr().await?;
send_member_removal_msg(context, chat_id, contact_id, &self_addr).await?;
send_member_removal_msg(context, &chat, contact_id, &self_addr).await?;
} else {
bail!("Cannot remove members from non-group chats.");
}
@@ -4241,14 +4241,18 @@ pub async fn remove_contact_from_chat(
async fn send_member_removal_msg(
context: &Context,
chat_id: ChatId,
chat: &Chat,
contact_id: ContactId,
addr: &str,
) -> Result<MsgId> {
let mut msg = Message::new(Viewtype::Text);
if contact_id == ContactId::SELF {
msg.text = stock_str::msg_group_left_local(context, ContactId::SELF).await;
if chat.typ == Chattype::InBroadcast {
msg.text = stock_str::msg_you_left_broadcast(context).await;
} else {
msg.text = stock_str::msg_group_left_local(context, ContactId::SELF).await;
}
} else {
msg.text = stock_str::msg_del_member_local(context, contact_id, ContactId::SELF).await;
}
@@ -4258,7 +4262,7 @@ async fn send_member_removal_msg(
msg.param
.set(Param::ContactAddedRemoved, contact_id.to_u32());
send_msg(context, chat_id, &mut msg).await
send_msg(context, chat.id, &mut msg).await
}
async fn set_group_explicitly_left(context: &Context, grpid: &str) -> Result<()> {

View File

@@ -3026,7 +3026,7 @@ async fn test_leave_broadcast() -> Result<()> {
}
/// Tests that if Bob leaves a broadcast channel with one device,
/// the other device shows a correct info message "You left.".
/// the other device shows a correct info message "You left the channel.".
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_leave_broadcast_multidevice() -> Result<()> {
let mut tcm = TestContextManager::new();
@@ -3061,10 +3061,7 @@ async fn test_leave_broadcast_multidevice() -> Result<()> {
assert_eq!(rcvd.chat_id, bob1_hello.chat_id);
assert!(rcvd.is_info());
assert_eq!(rcvd.get_info_type(), SystemMessage::MemberRemovedFromGroup);
assert_eq!(
rcvd.text,
stock_str::msg_group_left_local(bob1, ContactId::SELF).await
);
assert_eq!(rcvd.text, stock_str::msg_you_left_broadcast(bob1).await);
Ok(())
}

View File

@@ -1,6 +1,6 @@
//! # QR code generation module.
use anyhow::Result;
use anyhow::{Result, bail};
use base64::Engine as _;
use qrcodegen::{QrCode, QrCodeEcc};
@@ -108,8 +108,18 @@ async fn generate_join_group_qr_code(context: &Context, chat_id: ChatId) -> Resu
None => None,
};
let qrcode_description = match chat.typ {
crate::constants::Chattype::Group => {
stock_str::secure_join_group_qr_description(context, &chat).await
}
crate::constants::Chattype::OutBroadcast => {
stock_str::secure_join_broadcast_qr_description(context, &chat).await
}
_ => bail!("Unexpected chat type {}", chat.typ),
};
inner_generate_secure_join_qr_code(
&stock_str::secure_join_group_qr_description(context, &chat).await,
&qrcode_description,
&securejoin::get_securejoin_qr(context, Some(chat_id)).await?,
&color_int_to_hex_string(chat.get_color(context).await?),
avatar,

View File

@@ -3532,8 +3532,7 @@ async fn apply_in_broadcast_changes(
// The only member added/removed message that is ever sent is "I left.",
// so, this is the only case we need to handle here
if from_id == ContactId::SELF {
better_msg
.get_or_insert(stock_str::msg_group_left_local(context, ContactId::SELF).await);
better_msg.get_or_insert(stock_str::msg_you_left_broadcast(context).await);
}
}

View File

@@ -279,7 +279,7 @@ pub enum StockMessage {
#[strum(props(fallback = "Member %1$s removed by %2$s."))]
MsgDelMemberBy = 131,
#[strum(props(fallback = "You left."))]
#[strum(props(fallback = "You left the group."))]
MsgYouLeftGroup = 132,
#[strum(props(fallback = "Group left by %1$s."))]
@@ -439,6 +439,12 @@ https://delta.chat/donate"))]
#[strum(props(fallback = "Missed Call"))]
MissedCall = 198,
#[strum(props(fallback = "You left the channel."))]
MsgYouLeftBroadcast = 200,
#[strum(props(fallback = "Scan to join channel %1$s"))]
SecureJoinBrodcastQRDescription = 201,
}
impl StockMessage {
@@ -711,7 +717,7 @@ pub(crate) async fn msg_group_left_remote(context: &Context) -> String {
translated(context, StockMessage::MsgILeftGroup).await
}
/// Stock string: `You left.` or `Group left by %1$s.`.
/// Stock string: `You left the group.` or `Group left by %1$s.`.
pub(crate) async fn msg_group_left_local(context: &Context, by_contact: ContactId) -> String {
if by_contact == ContactId::SELF {
translated(context, StockMessage::MsgYouLeftGroup).await
@@ -722,6 +728,11 @@ pub(crate) async fn msg_group_left_local(context: &Context, by_contact: ContactI
}
}
/// Stock string: `You left the channel.`
pub(crate) async fn msg_you_left_broadcast(context: &Context) -> String {
translated(context, StockMessage::MsgYouLeftBroadcast).await
}
/// Stock string: `You reacted %1$s to "%2$s"` or `%1$s reacted %2$s to "%3$s"`.
pub(crate) async fn msg_reacted(
context: &Context,
@@ -857,13 +868,20 @@ pub(crate) async fn setup_contact_qr_description(
.replace1(&name)
}
/// Stock string: `Scan to join %1$s`.
/// Stock string: `Scan to join group %1$s`.
pub(crate) async fn secure_join_group_qr_description(context: &Context, chat: &Chat) -> String {
translated(context, StockMessage::SecureJoinGroupQRDescription)
.await
.replace1(chat.get_name())
}
/// Stock string: `Scan to join channel %1$s`.
pub(crate) async fn secure_join_broadcast_qr_description(context: &Context, chat: &Chat) -> String {
translated(context, StockMessage::SecureJoinBrodcastQRDescription)
.await
.replace1(chat.get_name())
}
/// Stock string: `%1$s verified.`.
#[allow(dead_code)]
pub(crate) async fn contact_verified(context: &Context, contact: &Contact) -> String {

View File

@@ -2,7 +2,7 @@ Group#Chat#10: Group chat [3 member(s)]
--------------------------------------------------------------------------------
Msg#10: info (Contact#Contact#Info): Messages are end-to-end encrypted. [NOTICED][INFO]
Msg#11🔒: (Contact#Contact#10): Hi! I created a group. [FRESH]
Msg#12🔒: Me (Contact#Contact#Self): You left. [INFO] √
Msg#12🔒: Me (Contact#Contact#Self): You left the group. [INFO] √
Msg#13🔒: (Contact#Contact#10): Member charlie@example.net added by alice@example.org. [FRESH][INFO]
Msg#14🔒: (Contact#Contact#10): What a silence! [FRESH]
--------------------------------------------------------------------------------