diff --git a/public/app.css b/public/app.css index 9c39475..b7f53d9 100644 --- a/public/app.css +++ b/public/app.css @@ -551,6 +551,7 @@ ul { .message__content { display: flex; flex-direction: column; + white-space: pre-line } .message__container__content { diff --git a/src/components/atoms/input.rs b/src/components/atoms/input.rs index 72b0e7b..a4b488f 100644 --- a/src/components/atoms/input.rs +++ b/src/components/atoms/input.rs @@ -74,7 +74,7 @@ pub fn MessageInput<'a>(cx: Scope<'a, MessageInputProps<'a>>) -> Element<'a> { onkeypress: move |event| cx.props.on_keypress.call(event) } - if cx.props.message.len() > 0 { + if !cx.props.message.is_empty() { match cx.props.itype { InputType::Message => render!( rsx!( diff --git a/src/components/atoms/textarea.rs b/src/components/atoms/textarea.rs index 3a4d611..ec07799 100644 --- a/src/components/atoms/textarea.rs +++ b/src/components/atoms/textarea.rs @@ -117,15 +117,19 @@ pub fn TextareaInput<'a>(cx: Scope<'a, TextareaInputProps<'a>>) -> Element<'a> { } } } - button { - class: "textarea__cta input__cta", - onclick: move |event| cx.props.on_click.call(event), - Icon { - stroke: "var(--icon-subdued)", - icon: Send, - height: 20, - width: 20 - } + if !cx.props.value.trim().is_empty() { + rsx!( + button { + class: "textarea__cta input__cta", + onclick: move |event| cx.props.on_click.call(event), + Icon { + stroke: "var(--icon-subdued)", + icon: Send, + height: 20, + width: 20 + } + } + ) } } } diff --git a/src/components/molecules/input_message.rs b/src/components/molecules/input_message.rs index 661b929..0a1aaa6 100644 --- a/src/components/molecules/input_message.rs +++ b/src/components/molecules/input_message.rs @@ -208,6 +208,7 @@ pub fn InputMessage<'a>(cx: Scope<'a, InputMessageProps<'a>>) -> Element<'a> { placeholder: cx.props.placeholder, on_input: move |event: FormEvent| { message_field.set(event.value.clone()); + log::info!("{:?}", event.value.clone()); }, on_keypress: move |event: KeyboardEvent| { let modifiers = event.modifiers(); @@ -215,8 +216,10 @@ pub fn InputMessage<'a>(cx: Scope<'a, InputMessageProps<'a>>) -> Element<'a> { match modifiers { keyboard_types::Modifiers::SHIFT => {} _ => { - if event.code() == keyboard_types::Code::Enter && message_field.get().len() > 0 { - cx.props.on_submit.call(FormMessageEvent { value: message_field.get().clone() }); + if event.code() == keyboard_types::Code::Enter { + if !message_field.get().trim().is_empty() { + cx.props.on_submit.call(FormMessageEvent { value: message_field.get().clone() }); + } message_field.set(String::from("")); } } diff --git a/src/components/molecules/list.rs b/src/components/molecules/list.rs index f3ed262..04922e4 100644 --- a/src/components/molecules/list.rs +++ b/src/components/molecules/list.rs @@ -58,7 +58,7 @@ pub fn List<'a>(cx: Scope<'a, ListProps<'a>>) -> Element<'a> { async move {} }); - let messages_list_skeleton = if cx.props.messages.len() > 0 { + let messages_list_skeleton = if !cx.props.messages.is_empty() { "" } else { "messages-list--skeleton" @@ -107,7 +107,7 @@ pub fn List<'a>(cx: Scope<'a, ListProps<'a>>) -> Element<'a> { } }, rsx!( - if cx.props.messages.len() > 0 { + if !cx.props.messages.is_empty() { rsx!(cx.props.messages.iter().enumerate().map(|(i, m)| { match m { TimelineRelation::None(message) => { diff --git a/src/components/molecules/rooms.rs b/src/components/molecules/rooms.rs index 85e3617..925b2bf 100644 --- a/src/components/molecules/rooms.rs +++ b/src/components/molecules/rooms.rs @@ -2,7 +2,7 @@ use dioxus::prelude::*; use crate::components::atoms::{room::RoomItem, RoomView, RoomViewSkeleton}; -#[derive(Clone, Debug, PartialEq, Hash, Eq)] +#[derive(Clone, Debug, PartialEq, Hash, Eq, Default)] pub struct CurrentRoom { pub id: String, pub name: String, @@ -22,7 +22,7 @@ pub struct RoomsListProps<'a> { } pub fn RoomsList<'a>(cx: Scope<'a, RoomsListProps<'a>>) -> Element<'a> { - let rooms_list_skeleton = if cx.props.rooms.len() > 0 { + let rooms_list_skeleton = if !cx.props.rooms.is_empty() { "" } else { "rooms-list--skeleton" @@ -31,7 +31,7 @@ pub fn RoomsList<'a>(cx: Scope<'a, RoomsListProps<'a>>) -> Element<'a> { cx.render(rsx! { section { class:"rooms-list {rooms_list_skeleton} fade-in", - if cx.props.rooms.len() > 0 { + if !cx.props.rooms.is_empty() { rsx!(cx.props.rooms.iter().map(|room| { rsx!(RoomView { key: "{room.id}", diff --git a/src/components/organisms/chat/active_room.rs b/src/components/organisms/chat/active_room.rs index 5f7d1d9..614e6c8 100644 --- a/src/components/organisms/chat/active_room.rs +++ b/src/components/organisms/chat/active_room.rs @@ -54,11 +54,7 @@ pub fn ActiveRoom(cx: Scope) -> Element { match evt.value { HeaderCallOptions::CLOSE => { nav.push(Route::ChatList {}); - room.set(CurrentRoom { - id: String::new(), - name: String::new(), - avatar_uri: None, - }); + room.set(CurrentRoom::default()); } _ => {} } diff --git a/src/components/organisms/menu/main.rs b/src/components/organisms/menu/main.rs index 765cf77..c76f029 100644 --- a/src/components/organisms/menu/main.rs +++ b/src/components/organisms/menu/main.rs @@ -19,11 +19,7 @@ pub struct TitleHeaderMain { } pub fn IndexMenu(cx: Scope) -> Element { - use_shared_state_provider::(cx, || CurrentRoom { - id: String::new(), - name: String::new(), - avatar_uri: None, - }); + use_shared_state_provider::(cx, || CurrentRoom::default()); use_shared_state_provider::(cx, || TitleHeaderMain { title: String::from("Chats"), }); diff --git a/src/hooks/use_attach.rs b/src/hooks/use_attach.rs index 3a9f3f0..7b82977 100644 --- a/src/hooks/use_attach.rs +++ b/src/hooks/use_attach.rs @@ -20,7 +20,6 @@ pub enum AttachError { UnknownContent, } -#[allow(clippy::needless_return)] pub fn use_attach(cx: &ScopeState) -> &UseAttachState { let attach = use_shared_state::>(cx).expect("Attach file not provided"); diff --git a/src/hooks/use_auth.rs b/src/hooks/use_auth.rs index d678893..e27b29d 100644 --- a/src/hooks/use_auth.rs +++ b/src/hooks/use_auth.rs @@ -84,7 +84,6 @@ impl LoginInfoBuilder { } } -#[allow(clippy::needless_return)] pub fn use_auth(cx: &ScopeState) -> &UseAuthState { let logged_in = use_shared_state::(cx).expect("Unable to use LoggedIn"); let login_cache = diff --git a/src/hooks/use_chat.rs b/src/hooks/use_chat.rs index 6ec2a99..2844aae 100644 --- a/src/hooks/use_chat.rs +++ b/src/hooks/use_chat.rs @@ -25,7 +25,6 @@ pub enum ChatError { TimelineError(TimelineError), } -#[allow(clippy::needless_return)] pub fn use_chat(cx: &ScopeState) -> &UseChatState { let i18 = use_i18(cx); let client = use_client(cx); diff --git a/src/hooks/use_client.rs b/src/hooks/use_client.rs index 38d9b72..0d6361a 100644 --- a/src/hooks/use_client.rs +++ b/src/hooks/use_client.rs @@ -7,7 +7,6 @@ use crate::{ services::matrix::matrix::create_client, utils::get_homeserver::Homeserver, MatrixClientState, }; -#[allow(clippy::needless_return)] pub fn use_client(cx: &ScopeState) -> &UseClientState { let matrix = use_shared_state::(cx).expect("Matrix client not provided"); diff --git a/src/hooks/use_init_app.rs b/src/hooks/use_init_app.rs index 4572bf0..cf9a4f4 100644 --- a/src/hooks/use_init_app.rs +++ b/src/hooks/use_init_app.rs @@ -27,7 +27,6 @@ pub struct MessageDispatchId { pub value: HashMap>, } -#[allow(clippy::needless_return)] pub fn use_init_app(cx: &ScopeState) { use_shared_state_provider::(cx, || LoggedIn(false)); use_shared_state_provider::(cx, || MatrixClientState { client: None }); @@ -39,11 +38,7 @@ pub fn use_init_app(cx: &ScopeState) { // Temporarily moved here because Route has an unexpected // change when we push a ChatRoom from a different nest route - use_shared_state_provider::(cx, || CurrentRoom { - id: String::from(""), - name: String::from(""), - avatar_uri: None, - }); + use_shared_state_provider::(cx, || CurrentRoom::default()); use_shared_state_provider::(cx, || Vec::new()); use_shared_state_provider::>(cx, || None); use_shared_state_provider::>(cx, || None); diff --git a/src/hooks/use_lifecycle.rs b/src/hooks/use_lifecycle.rs new file mode 100644 index 0000000..e8cf389 --- /dev/null +++ b/src/hooks/use_lifecycle.rs @@ -0,0 +1,25 @@ +use dioxus::prelude::*; + +pub fn use_lifecycle( + cx: &ScopeState, + create: C, + destroy: D, +) -> &LifeCycle { + cx.use_hook(|| { + create(); + LifeCycle { + ondestroy: Some(destroy), + } + }) +} + +pub struct LifeCycle { + ondestroy: Option, +} + +impl Drop for LifeCycle { + fn drop(&mut self) { + let f = self.ondestroy.take().unwrap(); + f(); + } +} diff --git a/src/hooks/use_listen_message.rs b/src/hooks/use_listen_message.rs index 595aa4e..6f7db85 100644 --- a/src/hooks/use_listen_message.rs +++ b/src/hooks/use_listen_message.rs @@ -22,7 +22,6 @@ use super::{ use_thread::use_thread, }; -#[allow(clippy::needless_return)] pub fn use_listen_message(cx: &ScopeState) -> &UseListenMessagesState { let i18 = use_i18(cx); let client = use_client(cx).get(); @@ -293,10 +292,9 @@ pub fn use_listen_message(cx: &ScopeState) -> &UseListenMessagesState { ]; async move { - client - .sync_once(SyncSettings::default()) - .await - .map_err(|_| ListenMessageError::FailedSync)?; + if let Err(e) = client.sync_once(SyncSettings::default()).await { + log::warn!("{e:?}") + }; let me = session.get().ok_or(ListenMessageError::SessionNotFound)?; diff --git a/src/hooks/use_messages.rs b/src/hooks/use_messages.rs index 8c0da88..cd172b1 100644 --- a/src/hooks/use_messages.rs +++ b/src/hooks/use_messages.rs @@ -2,7 +2,6 @@ use dioxus::prelude::*; use crate::{components::atoms::message::Messages, services::matrix::matrix::TimelineRelation}; -#[allow(clippy::needless_return)] pub fn use_messages(cx: &ScopeState) -> &UseMessagesState { let messages = use_shared_state::(cx).expect("Unable to use Messages"); diff --git a/src/hooks/use_modal.rs b/src/hooks/use_modal.rs index c915a37..c78e769 100644 --- a/src/hooks/use_modal.rs +++ b/src/hooks/use_modal.rs @@ -2,7 +2,6 @@ use dioxus::prelude::*; use crate::services::matrix::matrix::AccountInfo; -#[allow(clippy::needless_return)] pub fn use_modal(cx: &ScopeState) -> &UseModalState { let modal = use_shared_state::(cx).expect("Modal state not provided"); diff --git a/src/hooks/use_notification.rs b/src/hooks/use_notification.rs index e42c92f..7525841 100644 --- a/src/hooks/use_notification.rs +++ b/src/hooks/use_notification.rs @@ -24,7 +24,6 @@ pub enum NotificationType { None, } -#[allow(clippy::needless_return)] pub fn use_notification(cx: &ScopeState) -> &UseNotificationState { let notification = use_shared_state::(cx).expect("Notification not provided"); diff --git a/src/hooks/use_reply.rs b/src/hooks/use_reply.rs index 81f7934..050c170 100644 --- a/src/hooks/use_reply.rs +++ b/src/hooks/use_reply.rs @@ -2,7 +2,6 @@ use dioxus::prelude::*; use crate::components::molecules::input_message::ReplyingTo; -#[allow(clippy::needless_return)] pub fn use_reply(cx: &ScopeState) -> &UseReplyState { let replying_to = use_shared_state::>(cx).expect("Unable to read replying_to"); diff --git a/src/hooks/use_room.rs b/src/hooks/use_room.rs index c6c581d..ae226eb 100644 --- a/src/hooks/use_room.rs +++ b/src/hooks/use_room.rs @@ -2,7 +2,6 @@ use dioxus::prelude::*; use crate::components::molecules::rooms::CurrentRoom; -#[allow(clippy::needless_return)] pub fn use_room(cx: &ScopeState) -> &UseRoomState { let current_room = use_shared_state::(cx).expect("Unable to use CurrentRoom"); @@ -25,4 +24,8 @@ impl UseRoomState { let mut inner = self.inner.write(); *inner = room; } + + pub fn default(&self) { + self.set(CurrentRoom::default()) + } } diff --git a/src/hooks/use_send_attach.rs b/src/hooks/use_send_attach.rs index a241bfc..a772899 100644 --- a/src/hooks/use_send_attach.rs +++ b/src/hooks/use_send_attach.rs @@ -35,7 +35,6 @@ pub enum SendAttachStatus { None, } -#[allow(clippy::needless_return)] pub fn use_send_attach(cx: &ScopeState) -> &UseSendMessageState { let i18 = use_i18(cx); let client = use_client(cx); diff --git a/src/hooks/use_send_message.rs b/src/hooks/use_send_message.rs index 8a041d8..58760b8 100644 --- a/src/hooks/use_send_message.rs +++ b/src/hooks/use_send_message.rs @@ -44,7 +44,6 @@ pub enum MessageStatus { None, } -#[allow(clippy::needless_return)] pub fn use_send_message(cx: &ScopeState) -> &UseSendMessageState { let i18 = use_i18(cx); let client = use_client(cx); diff --git a/src/hooks/use_session.rs b/src/hooks/use_session.rs index 6068801..de9bbe1 100644 --- a/src/hooks/use_session.rs +++ b/src/hooks/use_session.rs @@ -11,7 +11,6 @@ use std::time::Duration; use crate::services::matrix::matrix::FullSession; -#[allow(clippy::needless_return)] pub fn use_session(cx: &ScopeState) -> &UseSessionState { let user = use_shared_state::>(cx).expect("Unable to use UserSession"); diff --git a/src/hooks/use_thread.rs b/src/hooks/use_thread.rs index 08a56eb..1eab0e3 100644 --- a/src/hooks/use_thread.rs +++ b/src/hooks/use_thread.rs @@ -2,7 +2,6 @@ use dioxus::prelude::*; use crate::services::matrix::matrix::TimelineThread; -#[allow(clippy::needless_return)] pub fn use_thread(cx: &ScopeState) -> &UseThreadState { let replying_to = use_shared_state::>(cx).expect("Unable to read TimelineThread"); diff --git a/src/lib.rs b/src/lib.rs index 2ede638..8a2d17d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,6 +14,7 @@ pub mod hooks { pub mod use_chat; pub mod use_client; pub mod use_init_app; + pub mod use_lifecycle; pub mod use_listen_message; pub mod use_messages; pub mod use_modal; diff --git a/src/pages/chat/chat_list.rs b/src/pages/chat/chat_list.rs index 5a4c5d7..b3b3f84 100644 --- a/src/pages/chat/chat_list.rs +++ b/src/pages/chat/chat_list.rs @@ -15,8 +15,7 @@ use crate::{ organisms::{chat::ActiveRoom, main::TitleHeaderMain}, }, hooks::{ - use_client::use_client, use_messages::use_messages, use_notification::use_notification, - use_room::use_room, use_session::use_session, + use_client::use_client, use_lifecycle::use_lifecycle, use_messages::use_messages, use_notification::use_notification, use_room::use_room, use_session::use_session }, services::matrix::matrix::{list_rooms_and_spaces, Conversations}, }; @@ -46,6 +45,17 @@ pub fn ChatList(cx: Scope) -> Element { let title_header = use_shared_state::(cx).expect("Unable to read title header"); let is_loading = use_state(cx, || false); + + let r = room.clone(); + use_lifecycle( + &cx, + || {}, + move || { + to_owned![r]; + + r.default(); + }, + ); let on_click_room = move |evt: FormRoomEvent| { room.set(evt.room.clone()); @@ -108,7 +118,7 @@ pub fn ChatList(cx: Scope) -> Element { section { class: "chat-list options", div { - if spaces.get().len() > 0 { + if !spaces.get().is_empty() { rsx!( ul { class: "chat-list__wrapper", @@ -120,6 +130,12 @@ pub fn ChatList(cx: Scope) -> Element { rooms_filtered.set(rooms.get().clone()); selected_space.set(key_chat_list_home.clone()); title_header.write().title = key_chat_list_home.clone(); + + if !rooms.get().iter().any(|r| { + room.get().id.eq(&r.id) + }) { + room.default() + } } } @@ -134,6 +150,12 @@ pub fn ChatList(cx: Scope) -> Element { rooms_filtered.set(value.clone()); selected_space.set(space.name.clone()); title_header.write().title = space.name.clone(); + + if !value.iter().any(|r| { + room.get().id.eq(&r.id) + }) { + room.default() + } } } ) @@ -171,7 +193,7 @@ pub fn ChatList(cx: Scope) -> Element { let default_rooms = all_rooms.get().iter().cloned().collect::>(); - if event.value.len() > 0 { + if !event.value.is_empty() { let x = default_rooms .iter() .filter(|r| r.name.to_lowercase().contains(&event.value.to_lowercase())) diff --git a/src/pages/chat/room/group.rs b/src/pages/chat/room/group.rs index 2534cbb..f03bd1a 100644 --- a/src/pages/chat/room/group.rs +++ b/src/pages/chat/room/group.rs @@ -148,13 +148,11 @@ pub fn RoomGroup(cx: Scope) -> Element { selected_users, attach, group_name, - navigation, key_common_error_user_id, key_group_error_profile, key_group_error_not_found, key_common_error_server, - notification, status, room @@ -294,7 +292,7 @@ pub fn RoomGroup(cx: Scope) -> Element { } else { render!(rsx! ( Avatar{ - name: if group_name.get().len() > 0 {String::from(group_name.get()) } else {String::from("X")}, + name: if !group_name.get().is_empty() { String::from(group_name.get()) } else { String::from("X") }, size: 80, uri: None } @@ -448,7 +446,7 @@ pub fn RoomGroup(cx: Scope) -> Element { user_id.set(event.value.clone()); }, on_keypress: move |event: KeyboardEvent| { - if event.code() == keyboard_types::Code::Enter && user_id.get().len() > 0 { + if event.code() == keyboard_types::Code::Enter && !user_id.get().is_empty() { let id = user_id.get(); task_search_user.send(id.to_string()) } @@ -471,7 +469,7 @@ pub fn RoomGroup(cx: Scope) -> Element { } }, users.read().deref().iter().map(|u| { - let checked = if let Some(_) = selected_users.read().profiles.clone().into_iter().find(|selected_p| selected_p.eq(&u.id)) {true} else {false} ; + let checked = if let Some(_) = selected_users.read().profiles.clone().into_iter().find(|selected_p| selected_p.eq(&u.id)) { true } else { false } ; rsx!( label { diff --git a/src/pages/chat/room/new.rs b/src/pages/chat/room/new.rs index eae4618..c5ef45f 100644 --- a/src/pages/chat/room/new.rs +++ b/src/pages/chat/room/new.rs @@ -148,7 +148,7 @@ pub fn RoomNew(cx: Scope) -> Element { user_id.set(event.value.clone()); }, on_keypress: move |event: KeyboardEvent| { - if event.code() == keyboard_types::Code::Enter && user_id.get().len() > 0 { + if event.code() == keyboard_types::Code::Enter && !user_id.get().is_empty() { let id = user_id.get(); task_search_user.send(id.to_string()) } diff --git a/src/pages/signup.rs b/src/pages/signup.rs index 0b30475..d05f7f8 100644 --- a/src/pages/signup.rs +++ b/src/pages/signup.rs @@ -382,7 +382,7 @@ pub fn Signup(cx: Scope) -> Element { }, on_keypress: move |event: KeyboardEvent| { info!("{:?}", event.code()); - if event.code() == keyboard_types::Code::Enter && homeserver.get().len() > 0 { + if event.code() == keyboard_types::Code::Enter && !homeserver.get().is_empty() { on_update_homeserver() } }, @@ -448,7 +448,7 @@ pub fn Signup(cx: Scope) -> Element { } )) }) - } else if flows.read().len() > 0 { + } else if !flows.read().is_empty() { let f = flows.read(); let flows = f.clone();