use std::fmt::{Display, Formatter, Result};
use crabstep::deserializer::iter::Property;
use crate::{
message_types::text_effects::text_effect::TextEffect, tables::messages::message::Message,
};
#[derive(Debug, PartialEq, Clone)]
pub enum BubbleComponent {
Run(Vec<AttributedRange>),
App,
Retracted,
}
#[derive(Debug, PartialEq, Eq)]
pub enum Service<'a> {
#[allow(non_camel_case_types)]
iMessage,
SMS,
RCS,
Satellite,
Other(&'a str),
Unknown,
}
impl<'a> Service<'a> {
#[must_use]
pub fn from_name(service: Option<&'a str>) -> Self {
if let Some(service_name) = service {
return match service_name.trim() {
"iMessage" => Service::iMessage,
"iMessageLite" => Service::Satellite,
"SMS" => Service::SMS,
"rcs" | "RCS" => Service::RCS,
service_name => Service::Other(service_name),
};
}
Service::Unknown
}
}
impl Display for Service<'_> {
fn fmt(&self, fmt: &mut Formatter<'_>) -> Result {
match self {
Service::iMessage => write!(fmt, "iMessage"),
Service::SMS => write!(fmt, "SMS"),
Service::RCS => write!(fmt, "RCS"),
Service::Satellite => write!(fmt, "Satellite"),
Service::Other(other) => write!(fmt, "{other}"),
Service::Unknown => write!(fmt, "Unknown"),
}
}
}
#[derive(Debug, PartialEq, Clone)]
pub struct AttributedRange {
pub start: usize,
pub end: usize,
pub effects: Vec<TextEffect>,
pub attachment: Option<AttachmentMeta>,
pub emoji_image: bool,
}
impl AttributedRange {
#[must_use]
pub fn text(start: usize, end: usize, effects: Vec<TextEffect>) -> Self {
Self {
start,
end,
effects,
attachment: None,
emoji_image: false,
}
}
#[must_use]
pub fn attachment(start: usize, end: usize, meta: AttachmentMeta) -> Self {
Self {
start,
end,
effects: vec![],
attachment: Some(meta),
emoji_image: false,
}
}
#[must_use]
pub fn inline_attachment(start: usize, end: usize, meta: AttachmentMeta) -> Self {
Self {
start,
end,
effects: vec![],
attachment: Some(meta),
emoji_image: true,
}
}
#[must_use]
pub fn is_attachment(&self) -> bool {
self.attachment.is_some()
}
}
#[derive(Debug, PartialEq, Default, Clone)]
pub struct AttachmentMeta {
pub guid: Option<String>,
pub transcription: Option<String>,
pub height: Option<f64>,
pub width: Option<f64>,
pub name: Option<String>,
}
impl AttachmentMeta {
pub(crate) fn set_from_key_value<'a>(&mut self, key: &str, value: &Property<'a, 'a>) {
match key {
"__kIMFileTransferGUIDAttributeName" => {
self.guid = value.as_string().map(String::from);
}
"IMAudioTranscription" => self.transcription = value.as_string().map(String::from),
"__kIMInlineMediaHeightAttributeName" => self.height = value.as_f64(),
"__kIMInlineMediaWidthAttributeName" => self.width = value.as_f64(),
"__kIMFilenameAttributeName" => self.name = value.as_string().map(String::from),
_ => {}
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SharedLocation {
Started,
Stopped,
}
#[derive(Debug, PartialEq, Eq)]
pub enum GroupAction<'a> {
ParticipantAdded(i32),
ParticipantRemoved(i32),
NameChange(&'a str),
ParticipantLeft,
GroupIconChanged,
GroupIconRemoved,
ChatBackgroundChanged,
ChatBackgroundRemoved,
PhoneNumberChanged(i32),
}
impl<'a> GroupAction<'a> {
#[must_use]
pub(crate) fn from_message(message: &'a Message) -> Option<Self> {
match (
message.item_type,
message.group_action_type,
message.other_handle,
&message.group_title,
) {
(1, 0, Some(who), _) if message.handle_id == Some(who) => {
Some(Self::PhoneNumberChanged(who))
}
(1, 0, Some(who), _) => Some(Self::ParticipantAdded(who)),
(1, 1, Some(who), _) => Some(Self::ParticipantRemoved(who)),
(2, _, _, Some(name)) => Some(Self::NameChange(name)),
(3, 0, _, _) => Some(Self::ParticipantLeft),
(3, 1, _, _) => Some(Self::GroupIconChanged),
(3, 2, _, _) => Some(Self::GroupIconRemoved),
(3, 4, _, _) => Some(Self::ChatBackgroundChanged),
(3, 6, _, _) => Some(Self::ChatBackgroundRemoved),
_ => None,
}
}
}