mirror of
https://github.com/chatmail/core.git
synced 2026-05-02 21:06:31 +03:00
feat: use dedicated 'call' viewtype (#7174)
a dedicated viewtype allows the UI to show a more advanced UI, but even when using the defaults, it has the advantage that incoming/outgoing and the date are directly visible. successor of https://github.com/chatmail/core/pull/6650
This commit is contained in:
@@ -4620,8 +4620,6 @@ int dc_msg_is_info (const dc_msg_t* msg);
|
|||||||
* and also offer a way to fix the encryption, eg. by a button offering a QR scan
|
* and also offer a way to fix the encryption, eg. by a button offering a QR scan
|
||||||
* - DC_INFO_WEBXDC_INFO_MESSAGE (32) - Info-message created by webxdc app sending `update.info`
|
* - DC_INFO_WEBXDC_INFO_MESSAGE (32) - Info-message created by webxdc app sending `update.info`
|
||||||
* - DC_INFO_CHAT_E2EE (50) - Info-message for "Chat is end-to-end-encrypted"
|
* - DC_INFO_CHAT_E2EE (50) - Info-message for "Chat is end-to-end-encrypted"
|
||||||
* - DC_INFO_OUTGOING_CALL (60) - Info-message refers to an outgoing call
|
|
||||||
* - DC_INFO_INCOMING_CALL (65) - Info-message refers to an incoming call
|
|
||||||
*
|
*
|
||||||
* For the messages that refer to a CONTACT,
|
* For the messages that refer to a CONTACT,
|
||||||
* dc_msg_get_info_contact_id() returns the contact ID.
|
* dc_msg_get_info_contact_id() returns the contact ID.
|
||||||
@@ -4678,8 +4676,6 @@ uint32_t dc_msg_get_info_contact_id (const dc_msg_t* msg);
|
|||||||
#define DC_INFO_INVALID_UNENCRYPTED_MAIL 13
|
#define DC_INFO_INVALID_UNENCRYPTED_MAIL 13
|
||||||
#define DC_INFO_WEBXDC_INFO_MESSAGE 32
|
#define DC_INFO_WEBXDC_INFO_MESSAGE 32
|
||||||
#define DC_INFO_CHAT_E2EE 50
|
#define DC_INFO_CHAT_E2EE 50
|
||||||
#define DC_INFO_OUTGOING_CALL 60
|
|
||||||
#define DC_INFO_INCOMING_CALL 65
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -5716,6 +5712,12 @@ int64_t dc_lot_get_timestamp (const dc_lot_t* lot);
|
|||||||
#define DC_MSG_VIDEOCHAT_INVITATION 70
|
#define DC_MSG_VIDEOCHAT_INVITATION 70
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Message indicating an incoming or outgoing call.
|
||||||
|
*/
|
||||||
|
#define DC_MSG_CALL 71
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The message is a webxdc instance.
|
* The message is a webxdc instance.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -324,6 +324,9 @@ pub enum MessageViewtype {
|
|||||||
/// Message is an invitation to a videochat.
|
/// Message is an invitation to a videochat.
|
||||||
VideochatInvitation,
|
VideochatInvitation,
|
||||||
|
|
||||||
|
/// Message is a call.
|
||||||
|
Call,
|
||||||
|
|
||||||
/// Message is an webxdc instance.
|
/// Message is an webxdc instance.
|
||||||
Webxdc,
|
Webxdc,
|
||||||
|
|
||||||
@@ -346,6 +349,7 @@ impl From<Viewtype> for MessageViewtype {
|
|||||||
Viewtype::Video => MessageViewtype::Video,
|
Viewtype::Video => MessageViewtype::Video,
|
||||||
Viewtype::File => MessageViewtype::File,
|
Viewtype::File => MessageViewtype::File,
|
||||||
Viewtype::VideochatInvitation => MessageViewtype::VideochatInvitation,
|
Viewtype::VideochatInvitation => MessageViewtype::VideochatInvitation,
|
||||||
|
Viewtype::Call => MessageViewtype::Call,
|
||||||
Viewtype::Webxdc => MessageViewtype::Webxdc,
|
Viewtype::Webxdc => MessageViewtype::Webxdc,
|
||||||
Viewtype::Vcard => MessageViewtype::Vcard,
|
Viewtype::Vcard => MessageViewtype::Vcard,
|
||||||
}
|
}
|
||||||
@@ -365,6 +369,7 @@ impl From<MessageViewtype> for Viewtype {
|
|||||||
MessageViewtype::Video => Viewtype::Video,
|
MessageViewtype::Video => Viewtype::Video,
|
||||||
MessageViewtype::File => Viewtype::File,
|
MessageViewtype::File => Viewtype::File,
|
||||||
MessageViewtype::VideochatInvitation => Viewtype::VideochatInvitation,
|
MessageViewtype::VideochatInvitation => Viewtype::VideochatInvitation,
|
||||||
|
MessageViewtype::Call => Viewtype::Call,
|
||||||
MessageViewtype::Webxdc => Viewtype::Webxdc,
|
MessageViewtype::Webxdc => Viewtype::Webxdc,
|
||||||
MessageViewtype::Vcard => Viewtype::Vcard,
|
MessageViewtype::Vcard => Viewtype::Vcard,
|
||||||
}
|
}
|
||||||
@@ -438,8 +443,6 @@ pub enum SystemMessageType {
|
|||||||
/// This message contains a users iroh node address.
|
/// This message contains a users iroh node address.
|
||||||
IrohNodeAddr,
|
IrohNodeAddr,
|
||||||
|
|
||||||
OutgoingCall,
|
|
||||||
IncomingCall,
|
|
||||||
CallAccepted,
|
CallAccepted,
|
||||||
CallEnded,
|
CallEnded,
|
||||||
}
|
}
|
||||||
@@ -468,8 +471,6 @@ impl From<deltachat::mimeparser::SystemMessage> for SystemMessageType {
|
|||||||
SystemMessage::IrohNodeAddr => SystemMessageType::IrohNodeAddr,
|
SystemMessage::IrohNodeAddr => SystemMessageType::IrohNodeAddr,
|
||||||
SystemMessage::SecurejoinWait => SystemMessageType::SecurejoinWait,
|
SystemMessage::SecurejoinWait => SystemMessageType::SecurejoinWait,
|
||||||
SystemMessage::SecurejoinWaitTimeout => SystemMessageType::SecurejoinWaitTimeout,
|
SystemMessage::SecurejoinWaitTimeout => SystemMessageType::SecurejoinWaitTimeout,
|
||||||
SystemMessage::OutgoingCall => SystemMessageType::OutgoingCall,
|
|
||||||
SystemMessage::IncomingCall => SystemMessageType::IncomingCall,
|
|
||||||
SystemMessage::CallAccepted => SystemMessageType::CallAccepted,
|
SystemMessage::CallAccepted => SystemMessageType::CallAccepted,
|
||||||
SystemMessage::CallEnded => SystemMessageType::CallEnded,
|
SystemMessage::CallEnded => SystemMessageType::CallEnded,
|
||||||
}
|
}
|
||||||
|
|||||||
114
src/calls.rs
114
src/calls.rs
@@ -4,6 +4,7 @@
|
|||||||
//! This means, the "Call ID" is a "Message ID" currently - similar to webxdc.
|
//! This means, the "Call ID" is a "Message ID" currently - similar to webxdc.
|
||||||
use crate::chat::{Chat, ChatId, send_msg};
|
use crate::chat::{Chat, ChatId, send_msg};
|
||||||
use crate::constants::Chattype;
|
use crate::constants::Chattype;
|
||||||
|
use crate::contact::ContactId;
|
||||||
use crate::context::Context;
|
use crate::context::Context;
|
||||||
use crate::events::EventType;
|
use crate::events::EventType;
|
||||||
use crate::headerdef::HeaderDef;
|
use crate::headerdef::HeaderDef;
|
||||||
@@ -82,11 +83,10 @@ impl Context {
|
|||||||
ensure!(chat.typ == Chattype::Single && !chat.is_self_talk());
|
ensure!(chat.typ == Chattype::Single && !chat.is_self_talk());
|
||||||
|
|
||||||
let mut call = Message {
|
let mut call = Message {
|
||||||
viewtype: Viewtype::Text,
|
viewtype: Viewtype::Call,
|
||||||
text: "Calling...".into(),
|
text: "Calling...".into(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
call.param.set_cmd(SystemMessage::OutgoingCall);
|
|
||||||
call.param.set(Param::WebrtcRoom, &place_call_info);
|
call.param.set(Param::WebrtcRoom, &place_call_info);
|
||||||
call.id = send_msg(self, chat_id, &mut call).await?;
|
call.id = send_msg(self, chat_id, &mut call).await?;
|
||||||
|
|
||||||
@@ -184,60 +184,61 @@ impl Context {
|
|||||||
mime_message: &MimeMessage,
|
mime_message: &MimeMessage,
|
||||||
call_id: MsgId,
|
call_id: MsgId,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
match mime_message.is_system_message {
|
if mime_message.is_call() {
|
||||||
SystemMessage::IncomingCall => {
|
let call = self.load_call_by_id(call_id).await?;
|
||||||
let call = self.load_call_by_id(call_id).await?;
|
if call.is_incoming {
|
||||||
if call.is_incoming {
|
if call.is_stale_call() {
|
||||||
if call.is_stale_call() {
|
call.update_text(self, "Missed call").await?;
|
||||||
call.update_text(self, "Missed call").await?;
|
self.emit_incoming_msg(call.msg.chat_id, call_id);
|
||||||
self.emit_incoming_msg(call.msg.chat_id, call_id);
|
|
||||||
} else {
|
|
||||||
self.emit_msgs_changed(call.msg.chat_id, call_id);
|
|
||||||
self.emit_event(EventType::IncomingCall {
|
|
||||||
msg_id: call.msg.id,
|
|
||||||
place_call_info: call.place_call_info.to_string(),
|
|
||||||
});
|
|
||||||
let wait = call.remaining_ring_seconds();
|
|
||||||
task::spawn(Context::emit_end_call_if_unaccepted(
|
|
||||||
self.clone(),
|
|
||||||
wait.try_into()?,
|
|
||||||
call.msg.id,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
self.emit_msgs_changed(call.msg.chat_id, call_id);
|
self.emit_msgs_changed(call.msg.chat_id, call_id);
|
||||||
}
|
self.emit_event(EventType::IncomingCall {
|
||||||
}
|
|
||||||
SystemMessage::CallAccepted => {
|
|
||||||
let call = self.load_call_by_id(call_id).await?;
|
|
||||||
self.emit_msgs_changed(call.msg.chat_id, call_id);
|
|
||||||
if call.is_incoming {
|
|
||||||
self.emit_event(EventType::IncomingCallAccepted {
|
|
||||||
msg_id: call.msg.id,
|
msg_id: call.msg.id,
|
||||||
accept_call_info: call.accept_call_info,
|
place_call_info: call.place_call_info.to_string(),
|
||||||
});
|
});
|
||||||
} else {
|
let wait = call.remaining_ring_seconds();
|
||||||
let accept_call_info = mime_message
|
task::spawn(Context::emit_end_call_if_unaccepted(
|
||||||
.get_header(HeaderDef::ChatWebrtcAccepted)
|
self.clone(),
|
||||||
.unwrap_or_default();
|
wait.try_into()?,
|
||||||
call.msg
|
call.msg.id,
|
||||||
.clone()
|
));
|
||||||
.mark_call_as_accepted(self, accept_call_info.to_string())
|
}
|
||||||
.await?;
|
} else {
|
||||||
self.emit_event(EventType::OutgoingCallAccepted {
|
self.emit_msgs_changed(call.msg.chat_id, call_id);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
match mime_message.is_system_message {
|
||||||
|
SystemMessage::CallAccepted => {
|
||||||
|
let call = self.load_call_by_id(call_id).await?;
|
||||||
|
self.emit_msgs_changed(call.msg.chat_id, call_id);
|
||||||
|
if call.is_incoming {
|
||||||
|
self.emit_event(EventType::IncomingCallAccepted {
|
||||||
|
msg_id: call.msg.id,
|
||||||
|
accept_call_info: call.accept_call_info,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
let accept_call_info = mime_message
|
||||||
|
.get_header(HeaderDef::ChatWebrtcAccepted)
|
||||||
|
.unwrap_or_default();
|
||||||
|
call.msg
|
||||||
|
.clone()
|
||||||
|
.mark_call_as_accepted(self, accept_call_info.to_string())
|
||||||
|
.await?;
|
||||||
|
self.emit_event(EventType::OutgoingCallAccepted {
|
||||||
|
msg_id: call.msg.id,
|
||||||
|
accept_call_info: accept_call_info.to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SystemMessage::CallEnded => {
|
||||||
|
let call = self.load_call_by_id(call_id).await?;
|
||||||
|
self.emit_msgs_changed(call.msg.chat_id, call_id);
|
||||||
|
self.emit_event(EventType::CallEnded {
|
||||||
msg_id: call.msg.id,
|
msg_id: call.msg.id,
|
||||||
accept_call_info: accept_call_info.to_string(),
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
SystemMessage::CallEnded => {
|
|
||||||
let call = self.load_call_by_id(call_id).await?;
|
|
||||||
self.emit_msgs_changed(call.msg.chat_id, call_id);
|
|
||||||
self.emit_event(EventType::CallEnded {
|
|
||||||
msg_id: call.msg.id,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -255,13 +256,10 @@ impl Context {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn load_call_by_message(&self, call: Message) -> Result<CallInfo> {
|
fn load_call_by_message(&self, call: Message) -> Result<CallInfo> {
|
||||||
ensure!(
|
ensure!(call.viewtype == Viewtype::Call);
|
||||||
call.get_info_type() == SystemMessage::IncomingCall
|
|
||||||
|| call.get_info_type() == SystemMessage::OutgoingCall
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(CallInfo {
|
Ok(CallInfo {
|
||||||
is_incoming: call.get_info_type() == SystemMessage::IncomingCall,
|
is_incoming: call.get_from_id() != ContactId::SELF,
|
||||||
is_accepted: call.is_call_accepted()?,
|
is_accepted: call.is_call_accepted()?,
|
||||||
place_call_info: call
|
place_call_info: call
|
||||||
.param
|
.param
|
||||||
@@ -284,10 +282,7 @@ impl Message {
|
|||||||
context: &Context,
|
context: &Context,
|
||||||
accept_call_info: String,
|
accept_call_info: String,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
ensure!(
|
ensure!(self.viewtype == Viewtype::Call);
|
||||||
self.get_info_type() == SystemMessage::IncomingCall
|
|
||||||
|| self.get_info_type() == SystemMessage::OutgoingCall
|
|
||||||
);
|
|
||||||
self.param.set_int(Param::Arg, 1);
|
self.param.set_int(Param::Arg, 1);
|
||||||
self.param.set(Param::WebrtcAccepted, accept_call_info);
|
self.param.set(Param::WebrtcAccepted, accept_call_info);
|
||||||
self.update_param(context).await?;
|
self.update_param(context).await?;
|
||||||
@@ -295,10 +290,7 @@ impl Message {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn is_call_accepted(&self) -> Result<bool> {
|
fn is_call_accepted(&self) -> Result<bool> {
|
||||||
ensure!(
|
ensure!(self.viewtype == Viewtype::Call);
|
||||||
self.get_info_type() == SystemMessage::IncomingCall
|
|
||||||
|| self.get_info_type() == SystemMessage::OutgoingCall
|
|
||||||
);
|
|
||||||
Ok(self.param.get_int(Param::Arg) == Some(1))
|
Ok(self.param.get_int(Param::Arg) == Some(1))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,9 +33,10 @@ async fn setup_call() -> Result<CallSetup> {
|
|||||||
let alice_call = Message::load_from_db(&alice, sent1.sender_msg_id).await?;
|
let alice_call = Message::load_from_db(&alice, sent1.sender_msg_id).await?;
|
||||||
let alice2_call = alice2.recv_msg(&sent1).await;
|
let alice2_call = alice2.recv_msg(&sent1).await;
|
||||||
for (t, m) in [(&alice, &alice_call), (&alice2, &alice2_call)] {
|
for (t, m) in [(&alice, &alice_call), (&alice2, &alice2_call)] {
|
||||||
assert!(m.is_info());
|
assert!(!m.is_info());
|
||||||
assert_eq!(m.get_info_type(), SystemMessage::OutgoingCall);
|
assert_eq!(m.viewtype, Viewtype::Call);
|
||||||
let info = t.load_call_by_id(m.id).await?;
|
let info = t.load_call_by_id(m.id).await?;
|
||||||
|
assert!(!info.is_incoming);
|
||||||
assert!(!info.is_accepted);
|
assert!(!info.is_accepted);
|
||||||
assert_eq!(info.place_call_info, "place_info");
|
assert_eq!(info.place_call_info, "place_info");
|
||||||
}
|
}
|
||||||
@@ -45,12 +46,13 @@ async fn setup_call() -> Result<CallSetup> {
|
|||||||
let bob_call = bob.recv_msg(&sent1).await;
|
let bob_call = bob.recv_msg(&sent1).await;
|
||||||
let bob2_call = bob2.recv_msg(&sent1).await;
|
let bob2_call = bob2.recv_msg(&sent1).await;
|
||||||
for (t, m) in [(&bob, &bob_call), (&bob2, &bob2_call)] {
|
for (t, m) in [(&bob, &bob_call), (&bob2, &bob2_call)] {
|
||||||
assert!(m.is_info());
|
assert!(!m.is_info());
|
||||||
assert_eq!(m.get_info_type(), SystemMessage::IncomingCall);
|
assert_eq!(m.viewtype, Viewtype::Call);
|
||||||
t.evtracker
|
t.evtracker
|
||||||
.get_matching(|evt| matches!(evt, EventType::IncomingCall { .. }))
|
.get_matching(|evt| matches!(evt, EventType::IncomingCall { .. }))
|
||||||
.await;
|
.await;
|
||||||
let info = t.load_call_by_id(m.id).await?;
|
let info = t.load_call_by_id(m.id).await?;
|
||||||
|
assert!(info.is_incoming);
|
||||||
assert!(!info.is_accepted);
|
assert!(!info.is_accepted);
|
||||||
assert_eq!(info.place_call_info, "place_info");
|
assert_eq!(info.place_call_info, "place_info");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2691,7 +2691,10 @@ impl ChatIdBlocked {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn prepare_msg_blob(context: &Context, msg: &mut Message) -> Result<()> {
|
async fn prepare_msg_blob(context: &Context, msg: &mut Message) -> Result<()> {
|
||||||
if msg.viewtype == Viewtype::Text || msg.viewtype == Viewtype::VideochatInvitation {
|
if msg.viewtype == Viewtype::Text
|
||||||
|
|| msg.viewtype == Viewtype::VideochatInvitation
|
||||||
|
|| msg.viewtype == Viewtype::Call
|
||||||
|
{
|
||||||
// the caller should check if the message text is empty
|
// the caller should check if the message text is empty
|
||||||
} else if msg.viewtype.has_file() {
|
} else if msg.viewtype.has_file() {
|
||||||
let viewtype_orig = msg.viewtype;
|
let viewtype_orig = msg.viewtype;
|
||||||
@@ -3167,6 +3170,7 @@ pub async fn send_edit_request(context: &Context, msg_id: MsgId, new_text: Strin
|
|||||||
original_msg.viewtype != Viewtype::VideochatInvitation,
|
original_msg.viewtype != Viewtype::VideochatInvitation,
|
||||||
"Cannot edit videochat invitations"
|
"Cannot edit videochat invitations"
|
||||||
);
|
);
|
||||||
|
ensure!(original_msg.viewtype != Viewtype::Call, "Cannot edit calls");
|
||||||
ensure!(
|
ensure!(
|
||||||
!original_msg.text.is_empty(), // avoid complexity in UI element changes. focus is typos and rewordings
|
!original_msg.text.is_empty(), // avoid complexity in UI element changes. focus is typos and rewordings
|
||||||
"Cannot add text"
|
"Cannot add text"
|
||||||
|
|||||||
@@ -973,8 +973,6 @@ impl Message {
|
|||||||
| SystemMessage::WebxdcStatusUpdate
|
| SystemMessage::WebxdcStatusUpdate
|
||||||
| SystemMessage::WebxdcInfoMessage
|
| SystemMessage::WebxdcInfoMessage
|
||||||
| SystemMessage::IrohNodeAddr
|
| SystemMessage::IrohNodeAddr
|
||||||
| SystemMessage::OutgoingCall
|
|
||||||
| SystemMessage::IncomingCall
|
|
||||||
| SystemMessage::CallAccepted
|
| SystemMessage::CallAccepted
|
||||||
| SystemMessage::CallEnded
|
| SystemMessage::CallEnded
|
||||||
| SystemMessage::Unknown => Ok(None),
|
| SystemMessage::Unknown => Ok(None),
|
||||||
@@ -2280,6 +2278,9 @@ pub enum Viewtype {
|
|||||||
/// Message is an invitation to a videochat.
|
/// Message is an invitation to a videochat.
|
||||||
VideochatInvitation = 70,
|
VideochatInvitation = 70,
|
||||||
|
|
||||||
|
/// Message is an incoming or outgoing call.
|
||||||
|
Call = 71,
|
||||||
|
|
||||||
/// Message is an webxdc instance.
|
/// Message is an webxdc instance.
|
||||||
Webxdc = 80,
|
Webxdc = 80,
|
||||||
|
|
||||||
@@ -2303,6 +2304,7 @@ impl Viewtype {
|
|||||||
Viewtype::Video => true,
|
Viewtype::Video => true,
|
||||||
Viewtype::File => true,
|
Viewtype::File => true,
|
||||||
Viewtype::VideochatInvitation => false,
|
Viewtype::VideochatInvitation => false,
|
||||||
|
Viewtype::Call => false,
|
||||||
Viewtype::Webxdc => true,
|
Viewtype::Webxdc => true,
|
||||||
Viewtype::Vcard => true,
|
Viewtype::Vcard => true,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
use std::collections::{BTreeSet, HashSet};
|
use std::collections::{BTreeSet, HashSet};
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
|
|
||||||
use anyhow::{Context as _, Result, anyhow, bail, ensure};
|
use anyhow::{Context as _, Result, bail, ensure};
|
||||||
use base64::Engine as _;
|
use base64::Engine as _;
|
||||||
use data_encoding::BASE32_NOPAD;
|
use data_encoding::BASE32_NOPAD;
|
||||||
use deltachat_contact_tools::sanitize_bidi_characters;
|
use deltachat_contact_tools::sanitize_bidi_characters;
|
||||||
@@ -1533,15 +1533,6 @@ impl MimeFactory {
|
|||||||
.into(),
|
.into(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
SystemMessage::OutgoingCall => {
|
|
||||||
headers.push((
|
|
||||||
"Chat-Content",
|
|
||||||
mail_builder::headers::raw::Raw::new("call").into(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
SystemMessage::IncomingCall => {
|
|
||||||
return Err(anyhow!("Unexpected incoming call rendering."));
|
|
||||||
}
|
|
||||||
SystemMessage::CallAccepted => {
|
SystemMessage::CallAccepted => {
|
||||||
headers.push((
|
headers.push((
|
||||||
"Chat-Content",
|
"Chat-Content",
|
||||||
@@ -1578,6 +1569,11 @@ impl MimeFactory {
|
|||||||
"Chat-Content",
|
"Chat-Content",
|
||||||
mail_builder::headers::raw::Raw::new("videochat-invitation").into(),
|
mail_builder::headers::raw::Raw::new("videochat-invitation").into(),
|
||||||
));
|
));
|
||||||
|
} else if msg.viewtype == Viewtype::Call {
|
||||||
|
headers.push((
|
||||||
|
"Chat-Content",
|
||||||
|
mail_builder::headers::raw::Raw::new("call").into(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
if msg.param.exists(Param::WebrtcRoom) {
|
if msg.param.exists(Param::WebrtcRoom) {
|
||||||
|
|||||||
@@ -217,17 +217,7 @@ pub enum SystemMessage {
|
|||||||
/// "Messages are end-to-end encrypted."
|
/// "Messages are end-to-end encrypted."
|
||||||
ChatE2ee = 50,
|
ChatE2ee = 50,
|
||||||
|
|
||||||
/// This system message represents an outgoing call.
|
|
||||||
/// This message is visible to the user as an "info" message.
|
|
||||||
OutgoingCall = 60,
|
|
||||||
|
|
||||||
/// This system message represents an incoming call.
|
|
||||||
/// This message is visible to the user as an "info" message.
|
|
||||||
IncomingCall = 65,
|
|
||||||
|
|
||||||
/// Message indicating that a call was accepted.
|
/// Message indicating that a call was accepted.
|
||||||
/// While the 1:1 call may be established elsewhere,
|
|
||||||
/// the message is still needed for a multidevice setup, so that other devices stop ringing.
|
|
||||||
CallAccepted = 66,
|
CallAccepted = 66,
|
||||||
|
|
||||||
/// Message indicating that a call was ended.
|
/// Message indicating that a call was ended.
|
||||||
@@ -692,12 +682,6 @@ impl MimeMessage {
|
|||||||
self.is_system_message = SystemMessage::ChatProtectionDisabled;
|
self.is_system_message = SystemMessage::ChatProtectionDisabled;
|
||||||
} else if value == "group-avatar-changed" {
|
} else if value == "group-avatar-changed" {
|
||||||
self.is_system_message = SystemMessage::GroupImageChanged;
|
self.is_system_message = SystemMessage::GroupImageChanged;
|
||||||
} else if value == "call" {
|
|
||||||
self.is_system_message = if self.incoming {
|
|
||||||
SystemMessage::IncomingCall
|
|
||||||
} else {
|
|
||||||
SystemMessage::OutgoingCall
|
|
||||||
};
|
|
||||||
} else if value == "call-accepted" {
|
} else if value == "call-accepted" {
|
||||||
self.is_system_message = SystemMessage::CallAccepted;
|
self.is_system_message = SystemMessage::CallAccepted;
|
||||||
} else if value == "call-ended" {
|
} else if value == "call-ended" {
|
||||||
@@ -738,6 +722,8 @@ impl MimeMessage {
|
|||||||
if let Some(room) = room {
|
if let Some(room) = room {
|
||||||
if content == "videochat-invitation" {
|
if content == "videochat-invitation" {
|
||||||
part.typ = Viewtype::VideochatInvitation;
|
part.typ = Viewtype::VideochatInvitation;
|
||||||
|
} else if content == "call" {
|
||||||
|
part.typ = Viewtype::Call
|
||||||
}
|
}
|
||||||
part.param.set(Param::WebrtcRoom, room);
|
part.param.set(Param::WebrtcRoom, room);
|
||||||
} else if let Some(accepted) = accepted {
|
} else if let Some(accepted) = accepted {
|
||||||
@@ -767,7 +753,10 @@ impl MimeMessage {
|
|||||||
| Viewtype::Vcard
|
| Viewtype::Vcard
|
||||||
| Viewtype::File
|
| Viewtype::File
|
||||||
| Viewtype::Webxdc => true,
|
| Viewtype::Webxdc => true,
|
||||||
Viewtype::Unknown | Viewtype::Text | Viewtype::VideochatInvitation => false,
|
Viewtype::Unknown
|
||||||
|
| Viewtype::Text
|
||||||
|
| Viewtype::VideochatInvitation
|
||||||
|
| Viewtype::Call => false,
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
let mut parts = std::mem::take(&mut self.parts);
|
let mut parts = std::mem::take(&mut self.parts);
|
||||||
@@ -1582,6 +1571,13 @@ impl MimeMessage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check if a message is a call.
|
||||||
|
pub(crate) fn is_call(&self) -> bool {
|
||||||
|
self.parts
|
||||||
|
.first()
|
||||||
|
.is_some_and(|part| part.typ == Viewtype::Call)
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn get_rfc724_mid(&self) -> Option<String> {
|
pub(crate) fn get_rfc724_mid(&self) -> Option<String> {
|
||||||
self.get_header(HeaderDef::MessageId)
|
self.get_header(HeaderDef::MessageId)
|
||||||
.and_then(|msgid| parse_message_id(msgid).ok())
|
.and_then(|msgid| parse_message_id(msgid).ok())
|
||||||
|
|||||||
@@ -1000,7 +1000,7 @@ pub(crate) async fn receive_imf_inner(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if mime_parser.is_system_message == SystemMessage::IncomingCall {
|
if mime_parser.is_call() {
|
||||||
context.handle_call_msg(&mime_parser, insert_msg_id).await?;
|
context.handle_call_msg(&mime_parser, insert_msg_id).await?;
|
||||||
} else if received_msg.hidden {
|
} else if received_msg.hidden {
|
||||||
// No need to emit an event about the changed message
|
// No need to emit an event about the changed message
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ impl Summary {
|
|||||||
let prefix = if msg.state == MessageState::OutDraft {
|
let prefix = if msg.state == MessageState::OutDraft {
|
||||||
Some(SummaryPrefix::Draft(stock_str::draft(context).await))
|
Some(SummaryPrefix::Draft(stock_str::draft(context).await))
|
||||||
} else if msg.from_id == ContactId::SELF {
|
} else if msg.from_id == ContactId::SELF {
|
||||||
if msg.is_info() {
|
if msg.is_info() || msg.viewtype == Viewtype::Call {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(SummaryPrefix::Me(stock_str::self_msg(context).await))
|
Some(SummaryPrefix::Me(stock_str::self_msg(context).await))
|
||||||
@@ -233,6 +233,16 @@ impl Message {
|
|||||||
type_file = self.param.get(Param::Summary1).map(|s| s.to_string());
|
type_file = self.param.get(Param::Summary1).map(|s| s.to_string());
|
||||||
append_text = true;
|
append_text = true;
|
||||||
}
|
}
|
||||||
|
Viewtype::Call => {
|
||||||
|
emoji = Some("📞");
|
||||||
|
type_name = Some(if self.from_id == ContactId::SELF {
|
||||||
|
"Outgoing call".to_string()
|
||||||
|
} else {
|
||||||
|
"Incoming call".to_string()
|
||||||
|
});
|
||||||
|
type_file = None;
|
||||||
|
append_text = false
|
||||||
|
}
|
||||||
Viewtype::Text | Viewtype::Unknown => {
|
Viewtype::Text | Viewtype::Unknown => {
|
||||||
emoji = None;
|
emoji = None;
|
||||||
if self.param.get_cmd() == SystemMessage::LocationOnly {
|
if self.param.get_cmd() == SystemMessage::LocationOnly {
|
||||||
|
|||||||
Reference in New Issue
Block a user