Show room avatars, handle edits and redactions
Also hide rooms with tombstone in roomlist if we've joined the room the tombstone points to. Fixed rooms joined from different clients having an empty display name.
This commit is contained in:
parent
f25d3b6821
commit
a8b76eaded
|
@ -9,12 +9,12 @@ edition = "2018"
|
|||
[dependencies]
|
||||
anyhow = "1.0"
|
||||
async-stream = "0.3"
|
||||
async-trait = "0.1"
|
||||
dirs-next = "2.0"
|
||||
futures = "0.3"
|
||||
iced = { git = "https://github.com/hecrj/iced", rev = "31522e3", features = ["debug", "image", "tokio"] }
|
||||
iced_futures = { git = "https://github.com/hecrj/iced", rev = "31522e3" }
|
||||
#iced_glow = { git = "https://github.com/hecrj/iced", rev = "31522e3", features = ["image"] }
|
||||
#matrix-sdk-common-macros = { git = "https://github.com/matrix-org/matrix-rust-sdk", rev = "e65915e" }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
time = "0.2"
|
||||
tokio = { version = "1.0", features = ["sync"] }
|
||||
|
@ -23,7 +23,7 @@ tracing-subscriber = { version = "0.2", features = ["parking_lot"] }
|
|||
|
||||
[dependencies.matrix-sdk]
|
||||
git = "https://github.com/matrix-org/matrix-rust-sdk"
|
||||
rev = "6435269"
|
||||
rev = "40c53f0"
|
||||
default_features = false
|
||||
features = ["encryption", "sqlite_cryptostore", "messages", "rustls-tls", "unstable-synapse-quirks"]
|
||||
|
||||
|
|
|
@ -22,9 +22,9 @@ pub type Error = anyhow::Error;
|
|||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct Session {
|
||||
access_token: String,
|
||||
user_id: UserId,
|
||||
device_id: Box<DeviceId>,
|
||||
homeserver: String,
|
||||
pub user_id: UserId,
|
||||
pub device_id: Box<DeviceId>,
|
||||
pub homeserver: String,
|
||||
}
|
||||
|
||||
impl From<Session> for matrix_sdk::Session {
|
||||
|
@ -121,7 +121,7 @@ pub async fn restore_login(session: Session) -> Result<(Client, Session), Error>
|
|||
let client = client(url)?;
|
||||
|
||||
client.restore_login(session.clone().into()).await?;
|
||||
//client.sync_once(SyncSettings::new()).await?;
|
||||
client.sync_once(SyncSettings::new()).await?;
|
||||
|
||||
Ok((client, session))
|
||||
}
|
||||
|
@ -162,7 +162,7 @@ fn write_session(session: &Session) -> Result<(), Error> {
|
|||
pub fn parse_mxc(url: &str) -> Result<(Box<ServerName>, String), Error> {
|
||||
let url = Url::parse(&url)?;
|
||||
anyhow::ensure!(url.scheme() == "mxc", "Not an mxc url");
|
||||
let host = url.host_str().ok_or(anyhow::anyhow!("url"))?;
|
||||
let host = url.host_str().ok_or_else(|| anyhow::anyhow!("url"))?;
|
||||
let server_name: Box<ServerName> = <&ServerName>::try_from(host)?.into();
|
||||
let path = url.path_segments().and_then(|mut p| p.next());
|
||||
match path {
|
||||
|
@ -190,6 +190,45 @@ pub enum Event {
|
|||
Token(String),
|
||||
}
|
||||
|
||||
/*pub enum Sync {
|
||||
MessageInvited()
|
||||
MessageJoined(RoomId, AnyRoomEvent),
|
||||
MessageLeft(RoomId, AnyRoomEvent),
|
||||
}
|
||||
|
||||
struct Emitter {
|
||||
client: Client,
|
||||
sender: tokio::sync::mpsc::Sender<Sync>,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl matrix_sdk::EventEmitter for Emitter {
|
||||
async fn on_room_message(
|
||||
&self,
|
||||
room: RoomState,
|
||||
message: &SyncMessageEvent<MessageEventContent>,
|
||||
) {
|
||||
let id = room.room_id().to_owned();
|
||||
let full = AnyRoomEvent::Message(
|
||||
AnyMessageEvent::RoomMessage(
|
||||
message
|
||||
.to_owned()
|
||||
.into_full_event(id.clone()),
|
||||
),
|
||||
);
|
||||
if let RoomState::Joined(room) = room {
|
||||
self.sender
|
||||
.send(Sync::MessageJoined(id, full))
|
||||
.await
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
|
||||
async fn on_room_member(&self, room: RoomState, member: &SyncStateEvent<MemberEventContent>) {
|
||||
|
||||
}
|
||||
}*/
|
||||
|
||||
impl<H, I> iced_futures::subscription::Recipe<H, I> for MatrixSync
|
||||
where
|
||||
H: std::hash::Hasher,
|
||||
|
@ -214,11 +253,18 @@ where
|
|||
.sync_with_callback(
|
||||
SyncSettings::new()
|
||||
.token(client.sync_token().await.unwrap())
|
||||
.timeout(Duration::from_secs(90))
|
||||
.full_state(true),
|
||||
.timeout(Duration::from_secs(30)),
|
||||
|response| async {
|
||||
sender.send(Event::Token(response.next_batch)).ok();
|
||||
//sender.send(Event::Token(response.next_batch)).ok();
|
||||
for (id, room) in response.rooms.join {
|
||||
for event in room.state.events {
|
||||
let id = id.clone();
|
||||
sender
|
||||
.send(Event::Room(AnyRoomEvent::State(
|
||||
event.into_full_event(id),
|
||||
)))
|
||||
.ok();
|
||||
}
|
||||
for event in room.timeline.events {
|
||||
let id = id.clone();
|
||||
let event = match event {
|
||||
|
|
272
src/ui.rs
272
src/ui.rs
|
@ -5,8 +5,8 @@ use std::{
|
|||
|
||||
use futures::executor::block_on;
|
||||
use iced::{
|
||||
Align, Application, Button, Column, Command, Container, Element, Length, Row, Rule, Scrollable,
|
||||
Subscription, Text, TextInput,
|
||||
Align, Application, Button, Column, Command, Container, Element, Image, Length, Row, Rule,
|
||||
Scrollable, Subscription, Text, TextInput,
|
||||
};
|
||||
use matrix_sdk::{
|
||||
api::r0::{
|
||||
|
@ -15,7 +15,10 @@ use matrix_sdk::{
|
|||
},
|
||||
events::{
|
||||
key::verification::cancel::CancelCode as VerificationCancelCode,
|
||||
room::{member::MembershipState, message::MessageEventContent},
|
||||
room::{
|
||||
member::MembershipState,
|
||||
message::{MessageEventContent, Relation, TextMessageEventContent},
|
||||
},
|
||||
AnyMessageEvent, AnyMessageEventContent, AnyRoomEvent, AnyStateEvent, AnyToDeviceEvent,
|
||||
},
|
||||
identifiers::{EventId, RoomAliasId, RoomId, UserId},
|
||||
|
@ -47,6 +50,8 @@ pub struct RoomEntry {
|
|||
pub alias: Option<RoomAliasId>,
|
||||
/// Defined display name
|
||||
pub display_name: Option<String>,
|
||||
/// mxc url for the rooms avatar
|
||||
pub avatar: Option<String>,
|
||||
/// Person we're in a direct message with
|
||||
pub direct: Option<UserId>,
|
||||
/// Cache of messages
|
||||
|
@ -54,12 +59,13 @@ pub struct RoomEntry {
|
|||
}
|
||||
|
||||
impl RoomEntry {
|
||||
pub fn from_sdk(room: &matrix_sdk::JoinedRoom) -> Self {
|
||||
pub async fn from_sdk(room: &matrix_sdk::JoinedRoom) -> Self {
|
||||
Self {
|
||||
direct: room.direct_target(),
|
||||
name: block_on(async { room.display_name().await }),
|
||||
name: room.display_name().await,
|
||||
topic: room.topic().unwrap_or_default(),
|
||||
alias: room.canonical_alias(),
|
||||
avatar: room.avatar_url(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
@ -99,9 +105,30 @@ impl MessageBuffer {
|
|||
};
|
||||
}
|
||||
|
||||
fn remove(&mut self, id: &EventId) {
|
||||
self.messages.retain(|e| e.event_id() != id);
|
||||
self.known_ids.remove(&id);
|
||||
}
|
||||
|
||||
/// Add a message to the buffer.
|
||||
pub fn push(&mut self, event: AnyRoomEvent) {
|
||||
self.known_ids.insert(event.event_id().clone());
|
||||
if let AnyRoomEvent::Message(AnyMessageEvent::RoomMessage(
|
||||
matrix_sdk::events::MessageEvent {
|
||||
content:
|
||||
MessageEventContent::Text(TextMessageEventContent {
|
||||
relates_to: Some(Relation::Replacement(ref replacement)),
|
||||
..
|
||||
}),
|
||||
..
|
||||
},
|
||||
)) = event
|
||||
{
|
||||
self.remove(&replacement.event_id);
|
||||
}
|
||||
if let AnyRoomEvent::Message(AnyMessageEvent::RoomRedaction(ref redaction)) = event {
|
||||
self.remove(&redaction.redacts);
|
||||
}
|
||||
self.messages.push(event);
|
||||
self.sort();
|
||||
self.update_time();
|
||||
|
@ -111,6 +138,23 @@ impl MessageBuffer {
|
|||
pub fn append(&mut self, mut events: Vec<AnyRoomEvent>) {
|
||||
events.retain(|e| !self.known_ids.contains(e.event_id()));
|
||||
for event in events.iter() {
|
||||
// Handle replacement
|
||||
if let AnyRoomEvent::Message(AnyMessageEvent::RoomMessage(
|
||||
matrix_sdk::events::MessageEvent {
|
||||
content:
|
||||
MessageEventContent::Text(TextMessageEventContent {
|
||||
relates_to: Some(Relation::Replacement(replacement)),
|
||||
..
|
||||
}),
|
||||
..
|
||||
},
|
||||
)) = event
|
||||
{
|
||||
self.remove(&replacement.event_id);
|
||||
}
|
||||
if let AnyRoomEvent::Message(AnyMessageEvent::RoomRedaction(redaction)) = event {
|
||||
self.remove(&redaction.redacts);
|
||||
}
|
||||
self.known_ids.insert(event.event_id().clone());
|
||||
}
|
||||
self.messages.append(&mut events);
|
||||
|
@ -216,6 +260,23 @@ impl MainView {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn room<'a>(&'a self, id: &RoomId) -> Result<&'a RoomEntry, Command<Message>> {
|
||||
match self.rooms.get(&id) {
|
||||
Some(room) => Ok(room),
|
||||
None => {
|
||||
let id = id.clone();
|
||||
let client = self.client.clone();
|
||||
let cmd = async move {
|
||||
let room = client.get_joined_room(&id).unwrap();
|
||||
let entry = RoomEntry::from_sdk(&room).await;
|
||||
Message::ResetRoom(id, entry)
|
||||
}
|
||||
.into();
|
||||
Err(cmd)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn view(&mut self) -> Element<Message> {
|
||||
// If settings view is open, display that instead
|
||||
if let Some(ref mut settings) = self.settings_view {
|
||||
|
@ -228,14 +289,23 @@ impl MainView {
|
|||
.height(Length::Fill)
|
||||
.scrollbar_width(5);
|
||||
|
||||
let client = &self.client;
|
||||
let rooms = &self.rooms;
|
||||
// Group by DM and group conversation
|
||||
#[allow(clippy::type_complexity)]
|
||||
let (mut dm_rooms, mut group_rooms): (
|
||||
Vec<(&RoomId, &RoomEntry)>,
|
||||
Vec<(&RoomId, &RoomEntry)>,
|
||||
) = self
|
||||
.rooms
|
||||
) = rooms
|
||||
.iter()
|
||||
// Hide if we're in the room the tombstone points to
|
||||
.filter(|(id, _)| {
|
||||
!client
|
||||
.get_joined_room(id)
|
||||
.and_then(|j| j.tombstone())
|
||||
.map(|t| rooms.contains_key(&t.replacement_room))
|
||||
.unwrap_or(false)
|
||||
})
|
||||
.partition(|(_, room)| room.direct.is_some());
|
||||
// Sort
|
||||
for list in [&mut dm_rooms, &mut group_rooms].iter_mut() {
|
||||
|
@ -243,7 +313,6 @@ impl MainView {
|
|||
RoomSorting::Alphabetic => {
|
||||
list.sort_unstable_by_key(|(_, room)| room.name.to_uppercase())
|
||||
}
|
||||
// TODO: fix this
|
||||
RoomSorting::Recent => list.sort_unstable_by(|(_, a), (_, b)| {
|
||||
a.messages.updated.cmp(&b.messages.updated).reverse()
|
||||
}),
|
||||
|
@ -255,21 +324,32 @@ impl MainView {
|
|||
self.group_buttons
|
||||
.resize_with(group_rooms.len(), Default::default);
|
||||
// Create buttons
|
||||
let images = &self.images;
|
||||
let dm_buttons: Vec<Button<_>> = self
|
||||
.dm_buttons
|
||||
.iter_mut()
|
||||
.enumerate()
|
||||
.map(|(idx, button)| {
|
||||
// TODO: highlight selected
|
||||
let (id, room) = dm_rooms[idx];
|
||||
let (id, room) = unsafe { dm_rooms.get_unchecked(idx) };
|
||||
let name = if room.name.is_empty() {
|
||||
"Missing name"
|
||||
} else {
|
||||
&room.name
|
||||
};
|
||||
Button::new(button, Text::new(name))
|
||||
let mut row = Row::new().align_items(Align::Center);
|
||||
if let Some(ref url) = room.avatar {
|
||||
if let Some(handle) = images.get(url) {
|
||||
row = row.push(
|
||||
Image::new(handle.clone())
|
||||
.width(20.into())
|
||||
.height(20.into()),
|
||||
);
|
||||
}
|
||||
}
|
||||
Button::new(button, row.push(Text::new(name)))
|
||||
.width(300.into())
|
||||
.on_press(Message::SelectRoom(id.to_owned()))
|
||||
.on_press(Message::SelectRoom(id.to_owned().to_owned()))
|
||||
})
|
||||
.collect();
|
||||
let room_buttons: Vec<Button<_>> = self
|
||||
|
@ -277,10 +357,25 @@ impl MainView {
|
|||
.iter_mut()
|
||||
.enumerate()
|
||||
.map(|(idx, button)| {
|
||||
let (id, room) = group_rooms[idx];
|
||||
Button::new(button, Text::new(&room.name))
|
||||
let (id, room) = unsafe { group_rooms.get_unchecked(idx) };
|
||||
let name = if room.name.is_empty() {
|
||||
"Missing name"
|
||||
} else {
|
||||
&room.name
|
||||
};
|
||||
let mut row = Row::new().align_items(Align::Center);
|
||||
if let Some(ref url) = room.avatar {
|
||||
if let Some(handle) = images.get(url) {
|
||||
row = row.push(
|
||||
Image::new(handle.clone())
|
||||
.width(20.into())
|
||||
.height(20.into()),
|
||||
);
|
||||
}
|
||||
}
|
||||
Button::new(button, row.push(Text::new(name)))
|
||||
.width(300.into())
|
||||
.on_press(Message::SelectRoom(id.to_owned()))
|
||||
.on_press(Message::SelectRoom(id.to_owned().to_owned()))
|
||||
})
|
||||
.collect();
|
||||
// Add buttons to container
|
||||
|
@ -322,11 +417,20 @@ impl MainView {
|
|||
room.name.clone()
|
||||
};
|
||||
|
||||
let mut title_row = Row::new().align_items(Align::Center);
|
||||
if let Some(handle) = room.avatar.as_deref().and_then(|a| images.get(a)) {
|
||||
title_row = title_row.push(
|
||||
Image::new(handle.to_owned())
|
||||
.width(24.into())
|
||||
.height(24.into()),
|
||||
);
|
||||
}
|
||||
message_col = message_col
|
||||
.push(Text::new(title).size(25))
|
||||
.push(title_row.push(Text::new(title).size(25)))
|
||||
.push(Rule::horizontal(2));
|
||||
let mut scroll = Scrollable::new(&mut self.message_scroll)
|
||||
.scrollbar_width(2)
|
||||
.spacing(4)
|
||||
.height(Length::Fill);
|
||||
// Backfill button or loading message
|
||||
let backfill: Element<_> = if room.messages.loading {
|
||||
|
@ -348,16 +452,28 @@ impl MainView {
|
|||
.into()
|
||||
};
|
||||
scroll = scroll.push(Container::new(backfill).width(Length::Fill).center_x());
|
||||
// mxid of most recent sender
|
||||
let mut last_sender: Option<UserId> = None;
|
||||
// Rendered display name of most recent sender
|
||||
let mut sender = String::from("Unknown sender");
|
||||
// Messages
|
||||
for event in room.messages.messages.iter() {
|
||||
#[allow(clippy::single_match)]
|
||||
match event {
|
||||
AnyRoomEvent::Message(AnyMessageEvent::RoomMessage(message)) => {
|
||||
let sender =
|
||||
match block_on(async { joined.get_member(&message.sender).await }) {
|
||||
// Display sender if message is from new sender
|
||||
if last_sender.as_ref() != Some(&message.sender) {
|
||||
last_sender = Some(message.sender.clone());
|
||||
sender = match block_on(async {
|
||||
joined.get_member(&message.sender).await
|
||||
}) {
|
||||
Some(member) => member.name().to_owned(),
|
||||
None => message.sender.to_string(),
|
||||
};
|
||||
scroll = scroll
|
||||
.push(iced::Space::with_height(4.into()))
|
||||
.push(Text::new(&sender).color([0.0, 0.0, 1.0]));
|
||||
}
|
||||
let content: Element<_> = match &message.content {
|
||||
MessageEventContent::Audio(audio) => {
|
||||
Text::new(format!("Audio message: {}", audio.body))
|
||||
|
@ -380,7 +496,7 @@ impl MainView {
|
|||
if let Some(ref url) = image.url {
|
||||
match self.images.get(url) {
|
||||
Some(handle) => Container::new(
|
||||
iced::Image::new(handle.to_owned())
|
||||
Image::new(handle.to_owned())
|
||||
.width(800.into())
|
||||
.height(1200.into()),
|
||||
)
|
||||
|
@ -414,13 +530,15 @@ impl MainView {
|
|||
};
|
||||
let row = Row::new()
|
||||
.spacing(5)
|
||||
.push(Text::new(sender).color([0.0, 0.0, 1.0]))
|
||||
.push(content)
|
||||
.push(Text::new(format_systime(message.origin_server_ts)));
|
||||
scroll = scroll.push(row);
|
||||
}
|
||||
AnyRoomEvent::Message(AnyMessageEvent::RoomEncrypted(_encrypted)) => {
|
||||
scroll = scroll.push(Text::new("Encrypted event").color([0.3, 0.3, 0.3]))
|
||||
scroll = scroll.push(Text::new("Encrypted event").color([0.3, 0.3, 0.3]));
|
||||
}
|
||||
AnyRoomEvent::RedactedMessage(_) => {
|
||||
scroll = scroll.push(Text::new("Deleted message").color([0.3, 0.3, 0.3]));
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
@ -468,14 +586,17 @@ impl MainView {
|
|||
Some(emojis) => {
|
||||
let mut row = Row::new().push(Text::new("Verify emojis match:"));
|
||||
for (emoji, name) in emojis.iter() {
|
||||
row = row.push(
|
||||
row = row
|
||||
.push(
|
||||
Column::new()
|
||||
.align_items(iced::Align::Center)
|
||||
.push(Text::new(*emoji).size(32))
|
||||
.push(Text::new(*name)),
|
||||
);
|
||||
)
|
||||
.spacing(5);
|
||||
}
|
||||
row.push(
|
||||
row.push(iced::Space::with_width(Length::Fill))
|
||||
.push(
|
||||
Button::new(&mut self.sas_accept_button, Text::new("Confirm"))
|
||||
.on_press(Message::VerificationConfirm),
|
||||
)
|
||||
|
@ -564,9 +685,10 @@ pub enum Message {
|
|||
// Main state messages
|
||||
/// Reset state for room
|
||||
ResetRoom(RoomId, RoomEntry),
|
||||
RoomName(RoomId, String),
|
||||
/// Get backfill for given room
|
||||
BackFill(RoomId),
|
||||
/// Received backfille
|
||||
/// Received backfill
|
||||
BackFilled(RoomId, MessageResponse),
|
||||
/// Fetch an image pointed to by an mxc url
|
||||
FetchImage(String),
|
||||
|
@ -719,24 +841,16 @@ impl Application for Retrix {
|
|||
*self = Retrix::LoggedIn(MainView::new(client.clone(), session));
|
||||
let mut commands: Vec<Command<Message>> = Vec::new();
|
||||
for room in client.joined_rooms().into_iter() {
|
||||
//let client = client.clone();
|
||||
let room = std::sync::Arc::new(room);
|
||||
let r = room.clone();
|
||||
let command: Command<_> = async move {
|
||||
let room = room.clone();
|
||||
let entry = RoomEntry::from_sdk(&room);
|
||||
|
||||
// Display name calculation for DMs is bronk so we're doing it
|
||||
// ourselves
|
||||
/*if let Some(ref direct) = entry.direct {
|
||||
let request = DisplayNameRequest::new(direct);
|
||||
if let Ok(response) = client.send(request).await {
|
||||
if let Some(name) = response.displayname {
|
||||
entry.name = name;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
Message::ResetRoom(room.room_id().to_owned(), entry)
|
||||
let entry = RoomEntry::from_sdk(&r).await;
|
||||
Message::ResetRoom(r.room_id().to_owned(), entry)
|
||||
}
|
||||
.into();
|
||||
if let Some(url) = room.avatar_url() {
|
||||
commands.push(async { Message::FetchImage(url) }.into())
|
||||
}
|
||||
commands.push(command);
|
||||
}
|
||||
return Command::batch(commands);
|
||||
|
@ -807,39 +921,58 @@ impl Application for Retrix {
|
|||
room.messages.push(AnyRoomEvent::State(event));
|
||||
}
|
||||
AnyStateEvent::RoomName(ref name) => {
|
||||
let room = view.rooms.entry(name.room_id.clone()).or_default();
|
||||
let id = name.room_id.clone();
|
||||
let room = view.rooms.entry(id.clone()).or_default();
|
||||
room.display_name = name.content.name().map(String::from);
|
||||
if let Some(joined) = view.client.get_joined_room(&name.room_id) {
|
||||
room.name = block_on(async { joined.display_name().await });
|
||||
}
|
||||
room.messages.push(AnyRoomEvent::State(event));
|
||||
let client = view.client.clone();
|
||||
return async move {
|
||||
let joined = client.get_joined_room(&id).unwrap();
|
||||
Message::RoomName(id, joined.display_name().await)
|
||||
}
|
||||
.into();
|
||||
}
|
||||
AnyStateEvent::RoomTopic(ref topic) => {
|
||||
let room = view.rooms.entry(topic.room_id.clone()).or_default();
|
||||
room.topic = topic.content.topic.clone();
|
||||
room.messages.push(AnyRoomEvent::State(event));
|
||||
}
|
||||
AnyStateEvent::RoomAvatar(ref avatar) => {
|
||||
let room = view.rooms.entry(avatar.room_id.clone()).or_default();
|
||||
room.messages.push(AnyRoomEvent::State(event));
|
||||
if let Some(url) = room.avatar.clone() {
|
||||
room.avatar = Some(url.clone());
|
||||
return async { Message::FetchImage(url) }.into();
|
||||
}
|
||||
}
|
||||
AnyStateEvent::RoomCreate(ref create) => {
|
||||
// Add room to the entry list
|
||||
let room = match view.client.get_joined_room(&create.room_id) {
|
||||
Some(joined) => view
|
||||
.rooms
|
||||
.entry(create.room_id.clone())
|
||||
.or_insert_with(|| RoomEntry::from_sdk(&joined)),
|
||||
None => view.rooms.entry(create.room_id.clone()).or_default(),
|
||||
};
|
||||
room.messages.push(AnyRoomEvent::State(event));
|
||||
let joined = view.client.get_joined_room(&create.room_id).unwrap();
|
||||
let id = create.room_id.clone();
|
||||
return async move {
|
||||
let mut entry = RoomEntry::from_sdk(&joined).await;
|
||||
entry.messages.push(AnyRoomEvent::State(event));
|
||||
Message::ResetRoom(id, entry)
|
||||
}
|
||||
.into();
|
||||
}
|
||||
AnyStateEvent::RoomMember(ref member) => {
|
||||
let room = view.rooms.entry(member.room_id.clone()).or_default();
|
||||
let client = view.client.clone();
|
||||
// If we left a room, remove it from the RoomEntry list
|
||||
let own_id = block_on(async { client.user_id().await })
|
||||
.unwrap()
|
||||
.to_string();
|
||||
if member.content.membership == MembershipState::Leave
|
||||
&& member.state_key == own_id
|
||||
{
|
||||
if member.state_key == view.session.user_id {
|
||||
match member.content.membership {
|
||||
MembershipState::Join => {
|
||||
let id = member.room_id.clone();
|
||||
return async move {
|
||||
let joined = client.get_joined_room(&id).unwrap();
|
||||
let entry = RoomEntry::from_sdk(&joined).await;
|
||||
|
||||
Message::ResetRoom(id, entry)
|
||||
}
|
||||
.into();
|
||||
}
|
||||
MembershipState::Leave => {
|
||||
// Deselect room if we're leaving selected room
|
||||
if view.selected.as_ref() == Some(&member.room_id) {
|
||||
view.selected = None;
|
||||
|
@ -847,6 +980,9 @@ impl Application for Retrix {
|
|||
view.rooms.remove(&member.room_id);
|
||||
return Command::none();
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
room.messages.push(AnyRoomEvent::State(event));
|
||||
}
|
||||
ref any => {
|
||||
|
@ -855,14 +991,20 @@ impl Application for Retrix {
|
|||
room.messages.push(AnyRoomEvent::State(event));
|
||||
}
|
||||
},
|
||||
_ => (),
|
||||
AnyRoomEvent::RedactedMessage(redacted) => {
|
||||
let room = view.rooms.entry(redacted.room_id().clone()).or_default();
|
||||
room.messages.push(AnyRoomEvent::RedactedMessage(redacted));
|
||||
}
|
||||
AnyRoomEvent::RedactedState(redacted) => {
|
||||
let room = view.rooms.entry(redacted.room_id().clone()).or_default();
|
||||
room.messages.push(AnyRoomEvent::RedactedState(redacted));
|
||||
}
|
||||
},
|
||||
matrix::Event::ToDevice(event) => match event {
|
||||
AnyToDeviceEvent::KeyVerificationStart(start) => {
|
||||
let client = view.client.clone();
|
||||
return Command::perform(
|
||||
async move {
|
||||
//tokio::time::delay_for(std::time::Duration::from_secs(2)).await;
|
||||
client.get_verification(&start.content.transaction_id).await
|
||||
},
|
||||
Message::SetVerification,
|
||||
|
@ -891,7 +1033,8 @@ impl Application for Retrix {
|
|||
.unwrap_or_else(|| view.sync_token.clone()),
|
||||
};
|
||||
return async move {
|
||||
let request = MessageRequest::backward(&id, &token);
|
||||
let mut request = MessageRequest::backward(&id, &token);
|
||||
request.limit = matrix_sdk::uint!(30);
|
||||
match client.room_messages(request).await {
|
||||
Ok(response) => Message::BackFilled(id, response),
|
||||
Err(e) => Message::ErrorMessage(e.to_string()),
|
||||
|
@ -935,10 +1078,6 @@ impl Application for Retrix {
|
|||
return async move { Message::ErrorMessage(e.to_string()) }.into()
|
||||
}
|
||||
};
|
||||
println!(
|
||||
"Getting '{}' from '{}', with url '{}'",
|
||||
&server, &path, &url
|
||||
);
|
||||
let client = view.client.clone();
|
||||
return async move {
|
||||
let request = ImageRequest::new(&path, &*server);
|
||||
|
@ -956,6 +1095,11 @@ impl Application for Retrix {
|
|||
Message::FetchedImage(url, handle) => {
|
||||
view.images.insert(url, handle);
|
||||
}
|
||||
Message::RoomName(id, name) => {
|
||||
if let Some(room) = view.rooms.get_mut(&id) {
|
||||
room.name = name;
|
||||
}
|
||||
}
|
||||
Message::SetVerification(v) => view.sas = v,
|
||||
Message::VerificationAccept => {
|
||||
let sas = match &view.sas {
|
||||
|
|
Loading…
Reference in a new issue