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, 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, PartialEq, Eq)]
189pub struct ChatMessageSnapshot {
190 pub id: String,
191 pub chat_id: String,
192 pub kind: ChatMessageKind,
193 pub author: String,
194 pub body: String,
195 pub attachments: Vec<MessageAttachmentSnapshot>,
196 pub reactions: Vec<MessageReactionSnapshot>,
197 pub reactors: Vec<MessageReactor>,
198 pub is_outgoing: bool,
199 pub created_at_secs: u64,
200 pub expires_at_secs: Option<u64>,
201 pub delivery: DeliveryState,
202 pub source_event_id: Option<String>,
209}
210
211#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
212pub struct TypingIndicatorSnapshot {
213 pub chat_id: String,
214 pub display_name: String,
215 pub expires_at_secs: u64,
216}
217
218#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
219pub struct ChatThreadSnapshot {
220 pub chat_id: String,
221 pub kind: ChatKind,
222 pub display_name: String,
223 pub subtitle: Option<String>,
224 pub picture_url: Option<String>,
225 pub member_count: u64,
226 pub last_message_preview: Option<String>,
227 pub last_message_at_secs: Option<u64>,
228 pub last_message_is_outgoing: Option<bool>,
229 pub last_message_delivery: Option<DeliveryState>,
230 pub unread_count: u64,
231 pub is_typing: bool,
232 pub is_muted: bool,
233}
234
235#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
236pub struct CurrentChatSnapshot {
237 pub chat_id: String,
238 pub kind: ChatKind,
239 pub display_name: String,
240 pub subtitle: Option<String>,
241 pub picture_url: Option<String>,
242 pub group_id: Option<String>,
243 pub member_count: u64,
244 pub message_ttl_seconds: Option<u64>,
245 pub is_muted: bool,
246 pub messages: Vec<ChatMessageSnapshot>,
247 pub typing_indicators: Vec<TypingIndicatorSnapshot>,
248}
249
250#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
251pub struct GroupMemberSnapshot {
252 pub owner_pubkey_hex: String,
253 pub display_name: String,
254 pub npub: String,
255 pub is_admin: bool,
256 pub is_creator: bool,
257 pub is_local_owner: bool,
258}
259
260#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
261pub struct GroupDetailsSnapshot {
262 pub group_id: String,
263 pub name: String,
264 pub picture_url: Option<String>,
265 pub created_by_display_name: String,
266 pub created_by_npub: String,
267 pub can_manage: bool,
268 pub is_muted: bool,
269 pub revision: u64,
270 pub members: Vec<GroupMemberSnapshot>,
271}
272
273#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
274pub struct RelayConnectionSnapshot {
275 pub url: String,
276 pub status: String,
277}
278
279#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
280pub struct NetworkStatusSnapshot {
281 pub relay_set_id: String,
282 pub relay_urls: Vec<String>,
283 pub relay_connections: Vec<RelayConnectionSnapshot>,
284 pub connected_relay_count: u64,
285 pub all_relays_offline_since_secs: Option<u64>,
286 pub syncing: bool,
287 pub pending_outbound_count: u64,
288 pub pending_group_control_count: u64,
289 pub recent_event_count: u64,
290 pub recent_log_count: u64,
291 pub last_debug_category: Option<String>,
292 pub last_debug_detail: Option<String>,
293}
294
295#[derive(uniffi::Record, Clone, Debug, Default, PartialEq, Eq)]
296pub struct MobilePushSessionSnapshot {
297 pub recipient_pubkey_hex: String,
298 pub display_name: String,
299 pub state_json: String,
300 pub tracked_sender_pubkeys: Vec<String>,
301 pub has_receiving_capability: bool,
302}
303
304#[derive(uniffi::Record, Clone, Debug, Default, PartialEq, Eq)]
305pub struct MobilePushSyncSnapshot {
306 pub owner_pubkey_hex: Option<String>,
307 pub message_author_pubkeys: Vec<String>,
308 pub invite_response_pubkeys: Vec<String>,
309 pub sessions: Vec<MobilePushSessionSnapshot>,
310}
311
312#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
313pub struct MobilePushNotificationResolution {
314 pub should_show: bool,
315 pub title: String,
316 pub body: String,
317 pub payload_json: String,
318}
319
320#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
321pub struct MobilePushSubscriptionRequest {
322 pub method: String,
323 pub url: String,
324 pub authorization_header: String,
325 pub body_json: Option<String>,
326}
327
328#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
329pub struct PublicInviteSnapshot {
330 pub url: String,
331}
332
333#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
334pub struct LinkDeviceSnapshot {
335 pub url: String,
336 pub device_input: String,
337}
338
339#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
340pub struct AppState {
341 pub rev: u64,
342 pub router: Router,
343 pub account: Option<AccountSnapshot>,
344 pub device_roster: Option<DeviceRosterSnapshot>,
345 pub busy: BusyState,
346 pub chat_list: Vec<ChatThreadSnapshot>,
347 pub current_chat: Option<CurrentChatSnapshot>,
348 pub group_details: Option<GroupDetailsSnapshot>,
349 pub public_invite: Option<PublicInviteSnapshot>,
350 pub link_device: Option<LinkDeviceSnapshot>,
351 pub network_status: Option<NetworkStatusSnapshot>,
352 pub mobile_push: MobilePushSyncSnapshot,
353 pub preferences: PreferencesSnapshot,
354 pub toast: Option<String>,
355}
356
357impl AppState {
358 pub fn empty() -> Self {
359 Self {
360 rev: 0,
361 router: Router {
362 default_screen: Screen::Welcome,
363 screen_stack: Vec::new(),
364 },
365 account: None,
366 device_roster: None,
367 busy: BusyState::default(),
368 chat_list: Vec::new(),
369 current_chat: None,
370 group_details: None,
371 public_invite: None,
372 link_device: None,
373 network_status: None,
374 mobile_push: MobilePushSyncSnapshot::default(),
375 preferences: PreferencesSnapshot::default(),
376 toast: None,
377 }
378 }
379}