use std::sync::Arc;
use parking_lot::Mutex;
use crossterm::event::KeyEvent;
use tokio::sync::mpsc;
use crate::state::{DisplayMessage, RoomMember, RoomSummary};
use crate::voip::CallState;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum RecoveryStatus {
#[default]
Disabled,
Incomplete,
Enabled,
}
#[derive(Clone)]
pub struct PasswordSender(pub Arc<Mutex<Option<tokio::sync::oneshot::Sender<String>>>>);
impl PasswordSender {
pub fn new(tx: tokio::sync::oneshot::Sender<String>) -> Self {
Self(Arc::new(Mutex::new(Some(tx))))
}
pub fn take(&self) -> Option<tokio::sync::oneshot::Sender<String>> {
self.0.lock().take()
}
}
impl std::fmt::Debug for PasswordSender {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("PasswordSender(..)")
}
}
#[derive(Debug, Clone)]
pub enum AppEvent {
Key(KeyEvent),
Resize,
Tick,
LoginSuccess {
user_id: String,
device_id: String,
homeserver: String,
},
LoginFailure(String),
RegisterFailure(String),
LoggedOut,
AutoLogin {
homeserver: String,
username: String,
password: String,
},
RoomListUpdated(Vec<RoomSummary>),
NewMessage {
room_id: String,
message: DisplayMessage,
},
MessagesLoaded {
room_id: String,
messages: Vec<DisplayMessage>,
has_more: bool,
pagination_token: Option<String>,
},
MessageSent {
room_id: String,
event_id: String,
body: String,
},
MessageEdited {
room_id: String,
target_event_id: String,
new_content: crate::state::MessageContent,
},
SendError {
error: String,
},
FetchError {
room_id: String,
error: String,
},
MembersLoaded {
room_id: String,
members: Vec<RoomMember>,
},
TypingUsersUpdated {
room_id: String,
user_ids: Vec<String>,
},
DmRoomReady {
room_id: String,
},
RoomCreated {
room_id: String,
},
SyncError(String),
SyncStatus(String),
SyncTokenUpdated(String),
CallMemberJoined {
room_id: String,
user_id: String,
},
CallMemberLeft {
room_id: String,
user_id: String,
},
CallParticipantUpdate {
participants: Vec<String>,
},
CallStateChanged {
room_id: String,
state: CallState,
},
CallError(String),
CallEnded,
RoomInfoLoaded {
room_id: String,
name: Option<String>,
topic: Option<String>,
history_visibility: String,
encrypted: bool,
},
RoomSettingUpdated {
room_id: String,
},
RoomSettingError {
error: String,
},
UserConfigLoaded {
display_name: Option<String>,
verified: bool,
recovery_status: RecoveryStatus,
},
UserConfigUpdated,
UserConfigError(String),
MicLevel(f32),
KeyRelease,
PttKeyCaptured(String),
PttListenerFailed(String),
RecoveryStateChecked(crate::state::RecoveryStage),
RecoveryKeyReady(String),
RecoveryHealingProgress(crate::state::HealingStep),
RecoveryRecovered,
RecoveryNeedPassword(PasswordSender),
RecoveryError(String),
VerificationRequestReceived {
sender: String,
},
VerificationSasEmoji {
emojis: Vec<(String, String)>,
sender: String,
},
VerificationCompleted,
VerificationCancelled {
reason: String,
},
VerificationError(String),
CrossSigningResetCompleted,
CrossSigningResetError(String),
MemberVerificationStatus {
room_id: String,
user_id: String,
verified: bool,
},
InviteAccepted {
room_id: String,
},
InviteDeclined,
UserInvited {
user_id: String,
},
InviteError {
error: String,
},
ReactionReceived {
room_id: String,
target_event_id: String,
reaction_event_id: String,
emoji_key: String,
sender: String,
},
ReactionSent {
room_id: String,
target_event_id: String,
reaction_event_id: String,
emoji_key: String,
sender: String,
},
ReactionRedacted {
room_id: String,
reaction_event_id: String,
},
MessageRedacted {
room_id: String,
target_event_id: String,
},
ImageLoaded {
event_id: String,
image_data: Vec<u8>,
},
ImageFailed {
event_id: String,
error: String,
},
}
pub type EventSender = mpsc::UnboundedSender<AppEvent>;
pub type EventReceiver = mpsc::UnboundedReceiver<AppEvent>;
pub fn event_channel() -> (EventSender, EventReceiver) {
mpsc::unbounded_channel()
}
pub trait WarnClosed<T> {
fn warn_closed(self, context: &str);
}
impl<T> WarnClosed<T> for Result<(), mpsc::error::SendError<T>> {
fn warn_closed(self, context: &str) {
if self.is_err() {
tracing::warn!("{context}: channel closed");
}
}
}