imessage_database/message_types/expressives.rs
1/*!
2 [Expressives](https://support.apple.com/en-us/HT206894) are effects that you can select by tapping and holding the send button.
3
4 The data is stored on messages through the `expressive_send_style_id` field.
5*/
6
7use std::fmt;
8
9/// Bubble effects are effects that alter the display of the chat bubble.
10///
11/// Read more [here](https://www.imore.com/how-to-use-bubble-and-screen-effects-imessage-iphone-ipad).
12#[derive(Debug, PartialEq, Eq, Clone, Copy)]
13pub enum BubbleEffect {
14 /// Creates a slam effect that makes the bubble appear to slam down onto the screen.
15 Slam,
16 /// Creates a loud effect that makes the bubble appear to enlarge temporarily.
17 Loud,
18 /// Creates a gentle effect that makes the bubble appear to shrink temporarily.
19 Gentle,
20 /// Creates an invisible ink effect that hides the message until the recipient swipes over it.
21 InvisibleInk,
22}
23
24/// Screen effects are effects that alter the entire background of the message view.
25///
26/// Read more [here](https://www.imore.com/how-to-use-bubble-and-screen-effects-imessage-iphone-ipad).
27#[derive(Debug, PartialEq, Eq, Clone, Copy)]
28pub enum ScreenEffect {
29 /// Creates a confetti effect that sprinkles confetti across the screen.
30 Confetti,
31 /// Creates an echo effect that sends multiple copies of the message across the screen.
32 Echo,
33 /// Creates a fireworks effect that displays colorful explosions on the screen.
34 Fireworks,
35 /// Creates a balloons effect that sends balloons floating up from the bottom of the screen.
36 Balloons,
37 /// Creates a heart effect that displays a large heart on the screen.
38 Heart,
39 /// Creates a laser light show effect across the screen.
40 Lasers,
41 /// Creates a shooting star effect that moves across the screen.
42 ShootingStar,
43 /// Creates a sparkle effect that twinkles across the screen.
44 Sparkles,
45 /// Creates a spotlight effect that highlights the message.
46 Spotlight,
47}
48
49/// Parsed value of a message's `expressive_send_style_id`.
50///
51/// Read more about expressive messages [here](https://www.imore.com/how-to-use-bubble-and-screen-effects-imessage-iphone-ipad).
52///
53/// Bubble:
54/// - `com.apple.MobileSMS.expressivesend.gentle`
55/// - `com.apple.MobileSMS.expressivesend.impact`
56/// - `com.apple.MobileSMS.expressivesend.invisibleink`
57/// - `com.apple.MobileSMS.expressivesend.loud`
58///
59/// Screen:
60/// - `com.apple.messages.effect.CKConfettiEffect`
61/// - `com.apple.messages.effect.CKEchoEffect`
62/// - `com.apple.messages.effect.CKFireworksEffect`
63/// - `com.apple.messages.effect.CKHappyBirthdayEffect`
64/// - `com.apple.messages.effect.CKHeartEffect`
65/// - `com.apple.messages.effect.CKLasersEffect`
66/// - `com.apple.messages.effect.CKShootingStarEffect`
67/// - `com.apple.messages.effect.CKSparklesEffect`
68/// - `com.apple.messages.effect.CKSpotlightEffect`
69#[derive(Debug, PartialEq, Eq, Clone, Copy)]
70pub enum Expressive<'a> {
71 /// Effect that uses the full message view.
72 Screen(ScreenEffect),
73 /// Effect that displays on a single bubble.
74 Bubble(BubbleEffect),
75 /// Unmapped raw `expressive_send_style_id` value.
76 Unknown(&'a str),
77 /// Message has no expressive send style.
78 None,
79}
80
81impl fmt::Display for Expressive<'_> {
82 /// Render the canonical user-facing label for this expressive (e.g. `Sent
83 /// with Confetti`). `None` renders to the empty string; `Unknown` renders
84 /// to the raw style id so unrecognized values still surface.
85 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
86 match self {
87 Self::Screen(ScreenEffect::Confetti) => f.write_str("Sent with Confetti"),
88 Self::Screen(ScreenEffect::Echo) => f.write_str("Sent with Echo"),
89 Self::Screen(ScreenEffect::Fireworks) => f.write_str("Sent with Fireworks"),
90 Self::Screen(ScreenEffect::Balloons) => f.write_str("Sent with Balloons"),
91 Self::Screen(ScreenEffect::Heart) => f.write_str("Sent with Heart"),
92 Self::Screen(ScreenEffect::Lasers) => f.write_str("Sent with Lasers"),
93 Self::Screen(ScreenEffect::ShootingStar) => f.write_str("Sent with Shooting Star"),
94 Self::Screen(ScreenEffect::Sparkles) => f.write_str("Sent with Sparkles"),
95 Self::Screen(ScreenEffect::Spotlight) => f.write_str("Sent with Spotlight"),
96 Self::Bubble(BubbleEffect::Slam) => f.write_str("Sent with Slam"),
97 Self::Bubble(BubbleEffect::Loud) => f.write_str("Sent with Loud"),
98 Self::Bubble(BubbleEffect::Gentle) => f.write_str("Sent with Gentle"),
99 Self::Bubble(BubbleEffect::InvisibleInk) => f.write_str("Sent with Invisible Ink"),
100 Self::Unknown(raw) => f.write_str(raw),
101 Self::None => Ok(()),
102 }
103 }
104}
105
106#[cfg(test)]
107mod tests {
108 use super::*;
109
110 #[test]
111 fn display_none_is_empty() {
112 assert_eq!(Expressive::None.to_string(), "");
113 }
114
115 #[test]
116 fn display_unknown_returns_raw_id() {
117 assert_eq!(Expressive::Unknown("custom.id").to_string(), "custom.id");
118 }
119
120 #[test]
121 fn display_screen_effects() {
122 let cases = [
123 (ScreenEffect::Confetti, "Sent with Confetti"),
124 (ScreenEffect::Echo, "Sent with Echo"),
125 (ScreenEffect::Fireworks, "Sent with Fireworks"),
126 (ScreenEffect::Balloons, "Sent with Balloons"),
127 (ScreenEffect::Heart, "Sent with Heart"),
128 (ScreenEffect::Lasers, "Sent with Lasers"),
129 (ScreenEffect::ShootingStar, "Sent with Shooting Star"),
130 (ScreenEffect::Sparkles, "Sent with Sparkles"),
131 (ScreenEffect::Spotlight, "Sent with Spotlight"),
132 ];
133 for (effect, expected) in cases {
134 assert_eq!(Expressive::Screen(effect).to_string(), expected);
135 }
136 }
137
138 #[test]
139 fn display_bubble_effects() {
140 let cases = [
141 (BubbleEffect::Slam, "Sent with Slam"),
142 (BubbleEffect::Loud, "Sent with Loud"),
143 (BubbleEffect::Gentle, "Sent with Gentle"),
144 (BubbleEffect::InvisibleInk, "Sent with Invisible Ink"),
145 ];
146 for (effect, expected) in cases {
147 assert_eq!(Expressive::Bubble(effect).to_string(), expected);
148 }
149 }
150}