use crate::DirectFileTransferSnapshot;
use serde::{Deserialize, Serialize};
#[derive(uniffi::Enum, Clone, Debug, PartialEq, Eq)]
pub enum Screen {
Welcome,
CreateAccount,
RestoreAccount,
RemoteSigner,
AddDevice,
ChatList,
NewChat,
NewGroup,
CreateInvite,
JoinInvite,
Settings,
Chat { chat_id: String },
DirectChatInfo { chat_id: String },
GroupDetails { group_id: String },
DeviceRoster,
DeviceRevoked,
}
#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
pub struct Router {
pub default_screen: Screen,
pub screen_stack: Vec<Screen>,
}
#[derive(uniffi::Record, Clone, Debug, Default, PartialEq, Eq)]
pub struct BusyState {
pub creating_account: bool,
pub restoring_session: bool,
pub linking_device: bool,
pub creating_chat: bool,
pub creating_group: bool,
pub sending_message: bool,
pub updating_roster: bool,
pub updating_group: bool,
pub creating_invite: bool,
pub accepting_invite: bool,
pub syncing_network: bool,
pub uploading_attachment: bool,
pub upload_progress: Option<UploadProgress>,
}
#[derive(uniffi::Record, Clone, Debug, Default, PartialEq, Eq)]
pub struct UploadProgress {
pub bytes_uploaded: u64,
pub total_bytes: u64,
}
#[derive(
uniffi::Record, Clone, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize,
)]
pub struct ChatMuteDeadline {
pub chat_id: String,
pub until_secs: u64,
}
#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
pub struct PreferencesSnapshot {
pub voice_calls_enabled: bool,
pub video_calls_enabled: bool,
pub call_quality: String,
pub call_max_bitrate_bps: u32,
pub send_typing_indicators: bool,
pub send_read_receipts: bool,
#[uniffi(default = true)]
pub allow_message_deletion_by_others: bool,
#[uniffi(default = false)]
pub hide_blocked_group_messages: bool,
pub desktop_notifications_enabled: bool,
pub invite_acceptance_notifications_enabled: bool,
pub startup_at_login_enabled: bool,
pub nearby_enabled: bool,
pub nearby_bluetooth_enabled: bool,
pub nearby_lan_enabled: bool,
pub nearby_show_in_chat_list: bool,
pub nearby_mailbag_enabled: bool,
pub nostr_relay_urls: Vec<String>,
pub image_proxy_enabled: bool,
pub image_proxy_fallback_enabled: bool,
pub image_proxy_url: String,
pub image_proxy_key_hex: String,
pub image_proxy_salt_hex: String,
pub muted_chat_ids: Vec<String>,
pub timed_chat_mutes: Vec<ChatMuteDeadline>,
#[uniffi(default = [])]
pub silent_mention_chat_ids: Vec<String>,
pub pinned_chat_ids: Vec<String>,
pub blocked_owner_pubkeys: Vec<String>,
pub accepted_owner_pubkeys: Vec<String>,
pub debug_logging_enabled: bool,
pub accept_unknown_direct_messages: bool,
pub mobile_push_server_url: String,
}
impl Default for PreferencesSnapshot {
fn default() -> Self {
Self {
voice_calls_enabled: true,
video_calls_enabled: true,
call_quality: "auto".into(),
call_max_bitrate_bps: 2_000_000,
send_typing_indicators: true,
send_read_receipts: true,
allow_message_deletion_by_others: true,
hide_blocked_group_messages: false,
desktop_notifications_enabled: true,
invite_acceptance_notifications_enabled: true,
startup_at_login_enabled: true,
nearby_enabled: true,
nearby_bluetooth_enabled: false,
nearby_lan_enabled: false,
nearby_show_in_chat_list: true,
nearby_mailbag_enabled: true,
nostr_relay_urls: crate::core::configured_relays(),
image_proxy_enabled: true,
image_proxy_fallback_enabled: false,
image_proxy_url: crate::image_proxy::DEFAULT_IMAGE_PROXY_URL.to_string(),
image_proxy_key_hex: crate::image_proxy::DEFAULT_IMAGE_PROXY_KEY_HEX.to_string(),
image_proxy_salt_hex: crate::image_proxy::DEFAULT_IMAGE_PROXY_SALT_HEX.to_string(),
muted_chat_ids: Vec::new(),
timed_chat_mutes: Vec::new(),
silent_mention_chat_ids: Vec::new(),
pinned_chat_ids: Vec::new(),
blocked_owner_pubkeys: Vec::new(),
accepted_owner_pubkeys: Vec::new(),
debug_logging_enabled: false,
accept_unknown_direct_messages: true,
mobile_push_server_url: String::new(),
}
}
}
#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
pub struct OutgoingAttachment {
pub file_path: String,
pub filename: String,
}
#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
pub struct AttachmentDownloadResult {
pub data_base64: Option<String>,
pub error: Option<String>,
}
#[derive(uniffi::Enum, Clone, Debug, PartialEq, Eq)]
pub enum DeviceAuthorizationState {
Authorized,
AwaitingApproval,
Revoked,
}
#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
pub struct AccountSnapshot {
pub public_key_hex: String,
pub npub: String,
pub display_name: String,
pub picture_url: Option<String>,
pub about: Option<String>,
pub device_public_key_hex: String,
pub device_npub: String,
pub has_owner_signing_authority: bool,
pub authorization_state: DeviceAuthorizationState,
}
#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
pub struct DeviceEntrySnapshot {
pub display_name: String,
pub device_pubkey_hex: String,
pub device_npub: String,
pub is_current_device: bool,
pub is_connected: bool,
pub is_authorized: bool,
pub is_stale: bool,
pub added_at_secs: Option<u64>,
pub device_label: Option<String>,
pub client_label: Option<String>,
}
#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
pub struct DeviceRosterSnapshot {
pub owner_public_key_hex: String,
pub owner_npub: String,
pub current_device_public_key_hex: String,
pub current_device_npub: String,
pub can_manage_devices: bool,
pub authorization_state: DeviceAuthorizationState,
pub devices: Vec<DeviceEntrySnapshot>,
}
#[derive(uniffi::Enum, Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub enum DeliveryState {
Queued,
Pending,
Sent,
Received,
Seen,
Failed,
}
#[derive(uniffi::Enum, Clone, Debug, PartialEq, Eq)]
pub enum ChatKind {
Direct,
Group,
}
#[derive(uniffi::Enum, Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub enum ChatMessageKind {
User,
System,
}
#[derive(uniffi::Record, Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub struct MessageAttachmentSnapshot {
#[serde(default)]
#[uniffi(default = [])]
pub uploaded_urls: Vec<String>,
pub nhash: String,
pub filename: String,
pub filename_encoded: String,
pub htree_url: String,
pub is_image: bool,
pub is_video: bool,
pub is_audio: bool,
}
#[derive(uniffi::Record, Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub struct MessageReactionSnapshot {
pub emoji: String,
pub count: u64,
pub reacted_by_me: bool,
}
#[derive(uniffi::Record, Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub struct MessageReactor {
pub author: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub display_name: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub picture_url: Option<String>,
pub emoji: String,
}
#[derive(uniffi::Record, Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub struct MessageRecipientDeliverySnapshot {
pub owner_pubkey_hex: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub display_name: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub picture_url: Option<String>,
pub delivery: DeliveryState,
pub updated_at_secs: u64,
}
#[derive(uniffi::Record, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Default)]
#[serde(default)]
pub struct MessageDeliveryTraceSnapshot {
pub outer_event_ids: Vec<String>,
pub pending_relay_event_ids: Vec<String>,
pub queued_protocol_targets: Vec<String>,
pub transport_channels: Vec<String>,
pub last_transport_error: Option<String>,
}
#[derive(uniffi::Record, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub struct CallHistorySnapshot {
pub call_id: String,
pub direction: String,
pub outcome: String,
pub video: bool,
pub started_at_secs: u64,
pub answered_at_secs: Option<u64>,
pub ended_at_secs: u64,
pub duration_secs: u64,
}
#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Hash)]
pub struct MessageEditSnapshot {
pub id: String,
pub body: String,
pub created_at_secs: u64,
}
#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
pub struct ChatMessageSnapshot {
#[uniffi(default = [])]
pub edit_history: Vec<MessageEditSnapshot>,
#[uniffi(default = false)]
pub deleted_for_everyone: bool,
#[uniffi(default = None)]
pub system_notice_owner_pubkey_hex: Option<String>,
#[uniffi(default = None)]
pub direct_transfer: Option<DirectFileTransferSnapshot>,
pub id: String,
pub chat_id: String,
pub kind: ChatMessageKind,
pub author: String,
pub author_owner_pubkey_hex: Option<String>,
pub author_picture_url: Option<String>,
pub body: String,
pub attachments: Vec<MessageAttachmentSnapshot>,
pub reactions: Vec<MessageReactionSnapshot>,
pub reactors: Vec<MessageReactor>,
pub is_outgoing: bool,
pub created_at_secs: u64,
pub expires_at_secs: Option<u64>,
pub delivery: DeliveryState,
pub recipient_deliveries: Vec<MessageRecipientDeliverySnapshot>,
pub delivery_trace: MessageDeliveryTraceSnapshot,
pub source_event_id: Option<String>,
#[uniffi(default = None)]
pub call: Option<CallHistorySnapshot>,
}
#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
pub struct TypingIndicatorSnapshot {
pub chat_id: String,
pub display_name: String,
pub expires_at_secs: u64,
}
#[derive(uniffi::Enum, Clone, Debug, PartialEq, Eq)]
pub enum SocialBadge {
Warning,
Following,
Friend,
Trusted,
Muted,
}
#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
pub struct SocialConnectionSnapshot {
pub badge: Option<SocialBadge>,
pub follow_distance: Option<u32>,
pub followed_by_friends: u32,
pub description: String,
#[uniffi(default = false)]
pub is_favorite: bool,
}
#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
pub struct MentionNotificationSnapshot {
pub message_id: String,
pub preview: String,
}
#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
pub struct ChatThreadSnapshot {
pub social_connection: Option<SocialConnectionSnapshot>,
pub chat_id: String,
pub kind: ChatKind,
pub display_name: String,
pub nickname: Option<String>,
pub contact_note: Option<String>,
pub profile_name: Option<String>,
pub subtitle: Option<String>,
pub picture_url: Option<String>,
pub about: Option<String>,
pub member_count: u64,
pub last_message_preview: Option<String>,
pub last_message_at_secs: Option<u64>,
pub last_message_is_outgoing: Option<bool>,
#[uniffi(default = None)]
pub last_message_id: Option<String>,
#[uniffi(default = [])]
pub unread_mention_messages: Vec<MentionNotificationSnapshot>,
pub last_message_delivery: Option<DeliveryState>,
pub unread_count: u64,
pub is_typing: bool,
pub is_muted: bool,
pub is_pinned: bool,
pub draft: String,
pub is_request: bool,
}
#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
pub struct ChatParticipantSnapshot {
pub social_connection: Option<SocialConnectionSnapshot>,
pub owner_pubkey_hex: String,
pub display_name: String,
pub picture_url: Option<String>,
pub is_local_owner: bool,
}
#[derive(uniffi::Enum, Clone, Debug, PartialEq, Eq)]
pub enum DirectChatCapabilityState {
Checking,
Available,
Unavailable,
CheckFailed,
}
#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
pub struct ContactIdentitySnapshot {
pub is_following: bool,
pub can_follow: bool,
pub updating_follow: bool,
pub first_seen_name: Option<String>,
pub saved_name: Option<String>,
pub pending_name: Option<String>,
pub is_favorite: bool,
}
#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
pub struct CurrentChatSnapshot {
pub contact_identity: Option<ContactIdentitySnapshot>,
pub social_connection: Option<SocialConnectionSnapshot>,
pub chat_id: String,
pub kind: ChatKind,
pub display_name: String,
pub nickname: Option<String>,
pub contact_note: Option<String>,
pub profile_name: Option<String>,
pub subtitle: Option<String>,
pub picture_url: Option<String>,
pub about: Option<String>,
pub group_id: Option<String>,
pub member_count: u64,
pub message_ttl_seconds: Option<u64>,
pub is_muted: bool,
pub participants: Vec<ChatParticipantSnapshot>,
pub messages: Vec<ChatMessageSnapshot>,
pub typing_indicators: Vec<TypingIndicatorSnapshot>,
pub draft: String,
pub is_request: bool,
pub direct_chat_capability: Option<DirectChatCapabilityState>,
}
#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
pub struct GroupMemberSnapshot {
pub social_connection: Option<SocialConnectionSnapshot>,
pub owner_pubkey_hex: String,
pub display_name: String,
pub npub: String,
pub picture_url: Option<String>,
pub is_admin: bool,
pub is_creator: bool,
pub is_local_owner: bool,
}
#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
pub struct GroupDetailsSnapshot {
pub group_id: String,
pub name: String,
pub picture_url: Option<String>,
pub about: Option<String>,
pub created_by_display_name: String,
pub created_by_npub: String,
pub can_manage: bool,
pub is_muted: bool,
pub revision: u64,
pub members: Vec<GroupMemberSnapshot>,
pub invite_links: Vec<GroupInviteSnapshot>,
}
#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
pub struct GroupInviteSnapshot {
pub id: String,
pub url: String,
pub title: String,
pub use_count: u32,
pub max_uses: Option<u32>,
pub expires_at: Option<u64>,
}
#[derive(uniffi::Record, Clone, Debug, Default, PartialEq, Eq)]
pub struct MutualGroupsSnapshot {
pub groups: Vec<ChatThreadSnapshot>,
}
#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
pub struct RelayConnectionSnapshot {
pub url: String,
pub status: String,
}
#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
pub struct NetworkStatusSnapshot {
pub relay_set_id: String,
pub relay_urls: Vec<String>,
pub relay_connections: Vec<RelayConnectionSnapshot>,
pub connected_relay_count: u64,
pub all_relays_offline_since_secs: Option<u64>,
pub syncing: bool,
pub pending_outbound_count: u64,
pub pending_group_control_count: u64,
pub recent_event_count: u64,
pub recent_log_count: u64,
pub last_debug_category: Option<String>,
pub last_debug_detail: Option<String>,
}
#[derive(uniffi::Record, Clone, Debug, Default, PartialEq, Eq)]
pub struct MobilePushSessionSnapshot {
pub recipient_pubkey_hex: String,
pub display_name: String,
pub state_json: String,
pub tracked_sender_pubkeys: Vec<String>,
pub has_receiving_capability: bool,
}
#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
pub struct MobilePushDelayedAuthor {
pub author_pubkey: String,
pub since_secs: u64,
}
#[derive(uniffi::Record, Clone, Debug, Default, PartialEq, Eq)]
pub struct MobilePushSyncSnapshot {
pub call_device_pubkey_hex: Option<String>,
pub owner_pubkey_hex: Option<String>,
pub message_author_pubkeys: Vec<String>,
pub delayed_message_authors: Vec<MobilePushDelayedAuthor>,
pub background_message_author_pubkeys: Vec<String>,
pub invite_response_pubkeys: Vec<String>,
pub sessions: Vec<MobilePushSessionSnapshot>,
}
#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
pub struct PeerProfileDebugSnapshot {
pub owner_pubkey_hex: String,
pub owner_npub: String,
pub direct_send_readiness: String,
pub roster_device_count: u64,
pub known_device_count: u64,
pub active_session_count: u64,
pub session_count: u64,
pub receiving_session_count: u64,
pub tracked_sender_count: u64,
pub recent_handshake_device_count: u64,
pub last_handshake_at_secs: Option<u64>,
pub tracked_for_messages: bool,
}
#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
pub struct MobilePushNotificationResolution {
pub should_show: bool,
pub title: String,
pub body: String,
pub payload_json: String,
}
#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
pub struct MobilePushSubscriptionRequest {
pub method: String,
pub url: String,
pub authorization_header: String,
pub body_json: Option<String>,
}
#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
pub struct MessageSearchHit {
pub chat_id: String,
pub message_id: String,
pub chat_display_name: String,
pub chat_picture_url: Option<String>,
pub chat_kind: ChatKind,
pub author_pubkey: String,
pub author_display_name: String,
pub author_picture_url: Option<String>,
pub body: String,
pub is_outgoing: bool,
pub created_at_secs: u64,
}
#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
pub struct FollowedUserSearchResult {
pub social_connection: Option<SocialConnectionSnapshot>,
pub owner_pubkey_hex: String,
pub display_label: String,
pub profile_label: Option<String>,
pub picture_url: Option<String>,
pub about: Option<String>,
pub user_id: String,
}
#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
pub struct SearchResultSnapshot {
pub query: String,
pub scope_chat_id: Option<String>,
pub people: Vec<FollowedUserSearchResult>,
pub contacts: Vec<ChatThreadSnapshot>,
pub groups: Vec<ChatThreadSnapshot>,
pub messages: Vec<MessageSearchHit>,
pub shortcut: Option<ChatInputShortcut>,
}
#[derive(uniffi::Enum, Clone, Debug, PartialEq, Eq)]
pub enum ChatInputShortcut {
DirectPeer {
peer_input: String,
display: String,
npub: String,
pubkey_hex: String,
},
Invite {
invite_input: String,
display: String,
},
}
impl SearchResultSnapshot {
pub fn empty(query: String, scope_chat_id: Option<String>) -> Self {
Self {
query,
scope_chat_id,
people: Vec::new(),
contacts: Vec::new(),
groups: Vec::new(),
messages: Vec::new(),
shortcut: None,
}
}
pub fn is_empty(&self) -> bool {
self.people.is_empty()
&& self.contacts.is_empty()
&& self.groups.is_empty()
&& self.messages.is_empty()
&& self.shortcut.is_none()
}
}
#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
pub struct PublicInviteSnapshot {
pub url: String,
pub legacy_url: String,
pub title: String,
#[uniffi(default = true)]
pub open_chat_on_join: bool,
}
#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
pub struct LinkDeviceSnapshot {
pub url: String,
pub device_input: String,
}
#[derive(uniffi::Enum, Clone, Debug, PartialEq, Eq)]
pub enum RemoteSignerPhase {
Connecting,
WaitingForSigner,
WaitingForApproval,
Finishing,
}
#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
pub struct RemoteSignerLoginSnapshot {
pub connection_uri: Option<String>,
pub phase: RemoteSignerPhase,
pub auth_url: Option<String>,
}
#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
pub struct CallSnapshot {
pub outgoing: bool,
pub target_bitrate_bps: u32,
pub key_frame_generation: u32,
pub media_connected: bool,
pub max_bitrate_bps: u32,
pub call_id: String,
pub chat_id: String,
pub peer_name: String,
pub phase: String,
pub video: bool,
pub video_capable: bool,
pub muted: bool,
pub remote_video: bool,
pub remote_muted: bool,
pub started_at_secs: u64,
pub connected_at_secs: Option<u64>,
pub end_reason: Option<String>,
}
#[derive(uniffi::Enum, Clone, Debug, PartialEq, Eq)]
pub enum DeviceHistorySyncPhase {
Discovering,
Transferring,
Waiting,
Complete,
}
#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
pub struct DeviceHistorySyncSnapshot {
pub phase: DeviceHistorySyncPhase,
pub imported_messages: u64,
pub total_messages: Option<u64>,
}
#[derive(uniffi::Record, Clone, Debug, PartialEq, Eq)]
pub struct AppState {
pub rev: u64,
pub call: Option<CallSnapshot>,
pub router: Router,
pub account: Option<AccountSnapshot>,
pub device_roster: Option<DeviceRosterSnapshot>,
pub device_history_sync: Option<DeviceHistorySyncSnapshot>,
pub busy: BusyState,
pub chat_list: Vec<ChatThreadSnapshot>,
pub blocked_people: Vec<FollowedUserSearchResult>,
pub message_visibility_revision: u64,
pub current_chat: Option<CurrentChatSnapshot>,
pub group_details: Option<GroupDetailsSnapshot>,
pub public_invite: Option<PublicInviteSnapshot>,
pub link_device: Option<LinkDeviceSnapshot>,
pub remote_signer_login: Option<RemoteSignerLoginSnapshot>,
pub network_status: Option<NetworkStatusSnapshot>,
pub mobile_push: MobilePushSyncSnapshot,
pub preferences: PreferencesSnapshot,
pub user_discovery_revision: u64,
pub user_discovery_syncing: bool,
pub toast: Option<String>,
}
impl AppState {
pub fn empty() -> Self {
Self {
rev: 0,
call: None,
router: Router {
default_screen: Screen::Welcome,
screen_stack: Vec::new(),
},
account: None,
device_roster: None,
device_history_sync: None,
busy: BusyState::default(),
chat_list: Vec::new(),
blocked_people: Vec::new(),
message_visibility_revision: 0,
current_chat: None,
group_details: None,
public_invite: None,
link_device: None,
remote_signer_login: None,
network_status: None,
mobile_push: MobilePushSyncSnapshot::default(),
preferences: PreferencesSnapshot::default(),
user_discovery_revision: 0,
user_discovery_syncing: false,
toast: None,
}
}
}