1use serde::{Deserialize, Serialize};
2
3#[derive(uniffi::Enum, Clone, Debug, PartialEq, Eq)]
4pub enum Screen {
5 Welcome,
6 CreateAccount,
7 RestoreAccount,
8 AddDevice,
9 ChatList,
10 NewChat,
11 NewGroup,
12 CreateInvite,
13 JoinInvite,
14 Settings,
15 Chat { chat_id: String },
16 GroupDetails { group_id: String },
17 DeviceRoster,
18 AwaitingDeviceApproval,
19 DeviceRevoked,
20}
21
22#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
23pub struct Router {
24 pub default_screen: Screen,
25 pub screen_stack: Vec<Screen>,
26}
27
28#[derive(uniffi::Record, Clone, Debug, Default, PartialEq, Eq)]
29pub struct BusyState {
30 pub creating_account: bool,
31 pub restoring_session: bool,
32 pub linking_device: bool,
33 pub creating_chat: bool,
34 pub creating_group: bool,
35 pub sending_message: bool,
36 pub updating_roster: bool,
37 pub updating_group: bool,
38 pub creating_invite: bool,
39 pub accepting_invite: bool,
40 pub syncing_network: bool,
41 pub uploading_attachment: bool,
42}
43
44#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
45pub struct PreferencesSnapshot {
46 pub send_typing_indicators: bool,
47 pub send_read_receipts: bool,
48 pub desktop_notifications_enabled: bool,
49 pub invite_acceptance_notifications_enabled: bool,
50 pub startup_at_login_enabled: bool,
51 pub nearby_bluetooth_enabled: bool,
52 pub nearby_lan_enabled: bool,
53 pub nostr_relay_urls: Vec<String>,
54 pub image_proxy_enabled: bool,
55 pub image_proxy_url: String,
56 pub image_proxy_key_hex: String,
57 pub image_proxy_salt_hex: String,
58 pub muted_chat_ids: Vec<String>,
59 pub mobile_push_server_url: String,
65}
66
67impl Default for PreferencesSnapshot {
68 fn default() -> Self {
69 Self {
70 send_typing_indicators: false,
71 send_read_receipts: true,
72 desktop_notifications_enabled: true,
73 invite_acceptance_notifications_enabled: true,
74 startup_at_login_enabled: true,
75 nearby_bluetooth_enabled: false,
76 nearby_lan_enabled: false,
77 nostr_relay_urls: crate::core::configured_relays(),
78 image_proxy_enabled: true,
79 image_proxy_url: crate::image_proxy::DEFAULT_IMAGE_PROXY_URL.to_string(),
80 image_proxy_key_hex: crate::image_proxy::DEFAULT_IMAGE_PROXY_KEY_HEX.to_string(),
81 image_proxy_salt_hex: crate::image_proxy::DEFAULT_IMAGE_PROXY_SALT_HEX.to_string(),
82 muted_chat_ids: Vec::new(),
83 mobile_push_server_url: String::new(),
84 }
85 }
86}
87
88#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
89pub struct OutgoingAttachment {
90 pub file_path: String,
91 pub filename: String,
92}
93
94#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
95pub struct AttachmentDownloadResult {
96 pub data_base64: Option<String>,
97 pub error: Option<String>,
98}
99
100#[derive(uniffi::Enum, Clone, Debug, PartialEq, Eq)]
101pub enum DeviceAuthorizationState {
102 Authorized,
103 AwaitingApproval,
104 Revoked,
105}
106
107#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
108pub struct AccountSnapshot {
109 pub public_key_hex: String,
110 pub npub: String,
111 pub display_name: String,
112 pub picture_url: Option<String>,
113 pub device_public_key_hex: String,
114 pub device_npub: String,
115 pub has_owner_signing_authority: bool,
116 pub authorization_state: DeviceAuthorizationState,
117}
118
119#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
120pub struct DeviceEntrySnapshot {
121 pub device_pubkey_hex: String,
122 pub device_npub: String,
123 pub is_current_device: bool,
124 pub is_authorized: bool,
125 pub is_stale: bool,
126 pub last_activity_secs: Option<u64>,
127}
128
129#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
130pub struct DeviceRosterSnapshot {
131 pub owner_public_key_hex: String,
132 pub owner_npub: String,
133 pub current_device_public_key_hex: String,
134 pub current_device_npub: String,
135 pub can_manage_devices: bool,
136 pub authorization_state: DeviceAuthorizationState,
137 pub devices: Vec<DeviceEntrySnapshot>,
138}
139
140#[derive(uniffi::Enum, Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
141pub enum DeliveryState {
142 Queued,
143 Pending,
144 Sent,
145 Received,
146 Seen,
147 Failed,
148}
149
150#[derive(uniffi::Enum, Clone, Debug, PartialEq, Eq)]
151pub enum ChatKind {
152 Direct,
153 Group,
154}
155
156#[derive(uniffi::Enum, Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
157pub enum ChatMessageKind {
158 User,
159 System,
160}
161
162#[derive(uniffi::Record, Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
163pub struct MessageAttachmentSnapshot {
164 pub nhash: String,
165 pub filename: String,
166 pub filename_encoded: String,
167 pub htree_url: String,
168 pub is_image: bool,
169 pub is_video: bool,
170 pub is_audio: bool,
171}
172
173#[derive(uniffi::Record, Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
174pub struct MessageReactionSnapshot {
175 pub emoji: String,
176 pub count: u64,
177 pub reacted_by_me: bool,
178}
179
180#[derive(uniffi::Record, Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
181pub struct MessageReactor {
182 pub author: String,
184 pub emoji: String,
186}
187
188#[derive(uniffi::Record, Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
189pub struct MessageRecipientDeliverySnapshot {
190 pub owner_pubkey_hex: String,
192 pub delivery: DeliveryState,
193 pub updated_at_secs: u64,
194}
195
196#[derive(uniffi::Record, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Default)]
197#[serde(default)]
198pub struct MessageDeliveryTraceSnapshot {
199 pub outer_event_ids: Vec<String>,
200 pub pending_relay_event_ids: Vec<String>,
201 pub queued_protocol_targets: Vec<String>,
202 pub target_device_ids: Vec<String>,
203 pub transport_channels: Vec<String>,
204 pub last_transport_error: Option<String>,
205}
206
207#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
208pub struct ChatMessageSnapshot {
209 pub id: String,
210 pub chat_id: String,
211 pub kind: ChatMessageKind,
212 pub author: String,
213 pub body: String,
214 pub attachments: Vec<MessageAttachmentSnapshot>,
215 pub reactions: Vec<MessageReactionSnapshot>,
216 pub reactors: Vec<MessageReactor>,
217 pub is_outgoing: bool,
218 pub created_at_secs: u64,
219 pub expires_at_secs: Option<u64>,
220 pub delivery: DeliveryState,
221 pub recipient_deliveries: Vec<MessageRecipientDeliverySnapshot>,
222 pub delivery_trace: MessageDeliveryTraceSnapshot,
223 pub source_event_id: Option<String>,
230}
231
232#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
233pub struct TypingIndicatorSnapshot {
234 pub chat_id: String,
235 pub display_name: String,
236 pub expires_at_secs: u64,
237}
238
239#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
240pub struct ChatThreadSnapshot {
241 pub chat_id: String,
242 pub kind: ChatKind,
243 pub display_name: String,
244 pub subtitle: Option<String>,
245 pub picture_url: Option<String>,
246 pub member_count: u64,
247 pub last_message_preview: Option<String>,
248 pub last_message_at_secs: Option<u64>,
249 pub last_message_is_outgoing: Option<bool>,
250 pub last_message_delivery: Option<DeliveryState>,
251 pub unread_count: u64,
252 pub is_typing: bool,
253 pub is_muted: bool,
254}
255
256#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
257pub struct CurrentChatSnapshot {
258 pub chat_id: String,
259 pub kind: ChatKind,
260 pub display_name: String,
261 pub subtitle: Option<String>,
262 pub picture_url: Option<String>,
263 pub group_id: Option<String>,
264 pub member_count: u64,
265 pub message_ttl_seconds: Option<u64>,
266 pub is_muted: bool,
267 pub messages: Vec<ChatMessageSnapshot>,
268 pub typing_indicators: Vec<TypingIndicatorSnapshot>,
269}
270
271#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
272pub struct GroupMemberSnapshot {
273 pub owner_pubkey_hex: String,
274 pub display_name: String,
275 pub npub: String,
276 pub is_admin: bool,
277 pub is_creator: bool,
278 pub is_local_owner: bool,
279}
280
281#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
282pub struct GroupDetailsSnapshot {
283 pub group_id: String,
284 pub name: String,
285 pub picture_url: Option<String>,
286 pub created_by_display_name: String,
287 pub created_by_npub: String,
288 pub can_manage: bool,
289 pub is_muted: bool,
290 pub revision: u64,
291 pub members: Vec<GroupMemberSnapshot>,
292}
293
294#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
295pub struct RelayConnectionSnapshot {
296 pub url: String,
297 pub status: String,
298}
299
300#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
301pub struct NetworkStatusSnapshot {
302 pub relay_set_id: String,
303 pub relay_urls: Vec<String>,
304 pub relay_connections: Vec<RelayConnectionSnapshot>,
305 pub connected_relay_count: u64,
306 pub all_relays_offline_since_secs: Option<u64>,
307 pub syncing: bool,
308 pub pending_outbound_count: u64,
309 pub pending_group_control_count: u64,
310 pub recent_event_count: u64,
311 pub recent_log_count: u64,
312 pub last_debug_category: Option<String>,
313 pub last_debug_detail: Option<String>,
314}
315
316#[derive(uniffi::Record, Clone, Debug, Default, PartialEq, Eq)]
317pub struct MobilePushSessionSnapshot {
318 pub recipient_pubkey_hex: String,
319 pub display_name: String,
320 pub state_json: String,
321 pub tracked_sender_pubkeys: Vec<String>,
322 pub has_receiving_capability: bool,
323}
324
325#[derive(uniffi::Record, Clone, Debug, Default, PartialEq, Eq)]
326pub struct MobilePushSyncSnapshot {
327 pub owner_pubkey_hex: Option<String>,
328 pub message_author_pubkeys: Vec<String>,
329 pub invite_response_pubkeys: Vec<String>,
330 pub sessions: Vec<MobilePushSessionSnapshot>,
331}
332
333#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
334pub struct MobilePushNotificationResolution {
335 pub should_show: bool,
336 pub title: String,
337 pub body: String,
338 pub payload_json: String,
339}
340
341#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
342pub struct MobilePushSubscriptionRequest {
343 pub method: String,
344 pub url: String,
345 pub authorization_header: String,
346 pub body_json: Option<String>,
347}
348
349#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
350pub struct PublicInviteSnapshot {
351 pub url: String,
352}
353
354#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
355pub struct LinkDeviceSnapshot {
356 pub url: String,
357 pub device_input: String,
358}
359
360#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
361pub struct AppState {
362 pub rev: u64,
363 pub router: Router,
364 pub account: Option<AccountSnapshot>,
365 pub device_roster: Option<DeviceRosterSnapshot>,
366 pub busy: BusyState,
367 pub chat_list: Vec<ChatThreadSnapshot>,
368 pub current_chat: Option<CurrentChatSnapshot>,
369 pub group_details: Option<GroupDetailsSnapshot>,
370 pub public_invite: Option<PublicInviteSnapshot>,
371 pub link_device: Option<LinkDeviceSnapshot>,
372 pub network_status: Option<NetworkStatusSnapshot>,
373 pub mobile_push: MobilePushSyncSnapshot,
374 pub preferences: PreferencesSnapshot,
375 pub toast: Option<String>,
376}
377
378impl AppState {
379 pub fn empty() -> Self {
380 Self {
381 rev: 0,
382 router: Router {
383 default_screen: Screen::Welcome,
384 screen_stack: Vec::new(),
385 },
386 account: None,
387 device_roster: None,
388 busy: BusyState::default(),
389 chat_list: Vec::new(),
390 current_chat: None,
391 group_details: None,
392 public_invite: None,
393 link_device: None,
394 network_status: None,
395 mobile_push: MobilePushSyncSnapshot::default(),
396 preferences: PreferencesSnapshot::default(),
397 toast: None,
398 }
399 }
400}