Compare commits
2 Commits
648be8ba72
...
27934c7fc9
Author | SHA1 | Date | |
---|---|---|---|
27934c7fc9
|
|||
9d95bd4481
|
@@ -44,6 +44,7 @@ pub trait RoomMessagingConsumerInterface {
|
||||
#[async_trait(?Send)]
|
||||
pub trait RoomMessagingProviderInterface {
|
||||
async fn get_avatar(&self, id: &RoomId) -> anyhow::Result<Option<Avatar>>;
|
||||
async fn join(&self, room_id: &RoomId) -> anyhow::Result<bool>;
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
|
@@ -314,4 +314,10 @@ impl RoomStoreConsumerInterface for Room {
|
||||
fn spaces(&self) -> &Vec<SpaceId> {
|
||||
&self.spaces
|
||||
}
|
||||
|
||||
async fn join(&self) {
|
||||
if let Some(messaging_provider) = &self.messaging_provider {
|
||||
let _ = messaging_provider.join(&self.id).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -29,11 +29,11 @@ pub trait RoomStoreConsumerInterface {
|
||||
fn is_direct(&self) -> Option<bool>;
|
||||
fn name(&self) -> Option<String>;
|
||||
fn topic(&self) -> Option<String>;
|
||||
fn spaces(&self) -> &Vec<SpaceId>;
|
||||
|
||||
#[allow(dead_code)]
|
||||
async fn avatar(&self) -> Option<Avatar>;
|
||||
|
||||
fn spaces(&self) -> &Vec<SpaceId>;
|
||||
async fn join(&self);
|
||||
}
|
||||
|
||||
pub trait RoomStoreProviderInterface {
|
||||
|
@@ -776,6 +776,19 @@ impl Client {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
async fn join_room(&self, room_id: &RoomId) -> anyhow::Result<bool> {
|
||||
let client = self.client.as_ref().unwrap();
|
||||
|
||||
if let Some(room) = client.get_room(room_id) {
|
||||
return match room.join().await {
|
||||
Ok(_) => Ok(true),
|
||||
Err(err) => Err(err.into()),
|
||||
};
|
||||
}
|
||||
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
async fn work(&mut self, mut rx: UnboundedReceiver<WorkerTask>) {
|
||||
while let Some(task) = rx.recv().await {
|
||||
self.run(task).await;
|
||||
@@ -820,6 +833,9 @@ impl Client {
|
||||
)
|
||||
.await;
|
||||
}
|
||||
WorkerTask::JoinRoom(id, reply) => {
|
||||
reply.send(self.join_room(&id).await).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -362,6 +362,10 @@ impl RoomMessagingProviderInterface for Requester {
|
||||
async fn get_avatar(&self, room_id: &RoomId) -> anyhow::Result<Option<Avatar>> {
|
||||
request_to_worker!(self, WorkerTask::GetRoomAvatar, room_id.clone())
|
||||
}
|
||||
|
||||
async fn join(&self, room_id: &RoomId) -> anyhow::Result<bool> {
|
||||
request_to_worker!(self, WorkerTask::JoinRoom, room_id.clone())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
|
@@ -23,6 +23,7 @@ pub enum WorkerTask {
|
||||
OwnedUserId,
|
||||
Sender<anyhow::Result<Option<Vec<u8>>>>,
|
||||
),
|
||||
JoinRoom(OwnedRoomId, Sender<anyhow::Result<bool>>),
|
||||
}
|
||||
|
||||
impl Debug for WorkerTask {
|
||||
@@ -61,6 +62,10 @@ impl Debug for WorkerTask {
|
||||
.field(room_id)
|
||||
.field(user_id)
|
||||
.finish(),
|
||||
WorkerTask::JoinRoom(room_id, _) => f
|
||||
.debug_tuple("WorkerTask::JoinRoom")
|
||||
.field(room_id)
|
||||
.finish(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,8 +1,7 @@
|
||||
use std::io::Cursor;
|
||||
|
||||
use image::imageops::FilterType;
|
||||
use image::io::Reader;
|
||||
use image::{DynamicImage, ImageFormat};
|
||||
use image::{DynamicImage, ImageFormat, ImageReader};
|
||||
use image::{GenericImage, RgbImage};
|
||||
use tracing::{error, warn};
|
||||
|
||||
@@ -13,7 +12,7 @@ cfg_if! {
|
||||
}
|
||||
|
||||
fn from_raw_to_image(raw: &Vec<u8>) -> Option<DynamicImage> {
|
||||
match Reader::new(Cursor::new(raw)).with_guessed_format() {
|
||||
match ImageReader::new(Cursor::new(raw)).with_guessed_format() {
|
||||
Ok(reader) => match reader.decode() {
|
||||
Ok(image) => return Some(image),
|
||||
Err(err) => error!("Unable to decode the image: {}", err),
|
||||
|
@@ -99,7 +99,7 @@ fn app() -> Element {
|
||||
}
|
||||
} else {
|
||||
rsx! {
|
||||
Login {},
|
||||
Login {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -43,7 +43,7 @@ macro_rules! svg_text_button {
|
||||
($name:ident,$style:ident,$icon:ident) => {
|
||||
pub fn $name(props: ButtonProps) -> Element {
|
||||
rsx! {
|
||||
style { {STYLE_SHEET} },
|
||||
style { {STYLE_SHEET} }
|
||||
|
||||
Button {
|
||||
id: props.id,
|
||||
@@ -79,7 +79,7 @@ pub struct ButtonProps {
|
||||
|
||||
pub fn Button(props: ButtonProps) -> Element {
|
||||
rsx! {
|
||||
style { {STYLE_SHEET} },
|
||||
style { {STYLE_SHEET} }
|
||||
|
||||
button {
|
||||
id: props.id,
|
||||
@@ -96,8 +96,8 @@ pub fn Button(props: ButtonProps) -> Element {
|
||||
}
|
||||
},
|
||||
|
||||
{props.children},
|
||||
},
|
||||
{props.children}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -2,6 +2,7 @@ use std::{rc::Rc, time::Duration};
|
||||
|
||||
use base64::{engine::general_purpose, Engine as _};
|
||||
use dioxus::prelude::*;
|
||||
use futures_util::StreamExt;
|
||||
use tracing::{debug, warn};
|
||||
|
||||
use super::{button::Button, icons::SearchIcon, text_input::TextInput};
|
||||
@@ -431,11 +432,16 @@ pub fn Search() -> Element {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
enum ConversationOptionsMenuActions {
|
||||
Join(RoomId),
|
||||
Close,
|
||||
}
|
||||
|
||||
#[component]
|
||||
fn ConversationOptionsMenu(
|
||||
room_id: RoomId,
|
||||
on_close: EventHandler,
|
||||
on_join: EventHandler,
|
||||
callbacks: Coroutine<ConversationOptionsMenuActions>,
|
||||
) -> Element {
|
||||
let room = STORE.read().rooms().get(&room_id).unwrap().signal();
|
||||
|
||||
@@ -450,7 +456,7 @@ fn ConversationOptionsMenu(
|
||||
|
||||
div {
|
||||
class: ClassName::CONVERSATION_OPTIONS_MENU_INNER_AVATAR,
|
||||
ConversationAvatar { room_id }
|
||||
ConversationAvatar { room_id: room_id.clone() }
|
||||
}
|
||||
|
||||
div {
|
||||
@@ -477,7 +483,9 @@ fn ConversationOptionsMenu(
|
||||
div {
|
||||
class: ClassName::CONVERSATION_OPTIONS_MENU_INNER_CLOSE_BUTTON,
|
||||
RejectButton {
|
||||
onclick: move |_| on_close(())
|
||||
onclick: move |_| {
|
||||
callbacks.send(ConversationOptionsMenuActions::Close);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -485,8 +493,8 @@ fn ConversationOptionsMenu(
|
||||
class: ClassName::CONVERSATION_OPTIONS_MENU_INNER_JOIN_BUTTON,
|
||||
JoinButton {
|
||||
onclick: move |_| {
|
||||
on_join(());
|
||||
on_close(());
|
||||
callbacks.send(ConversationOptionsMenuActions::Join(room_id.clone()));
|
||||
callbacks.send(ConversationOptionsMenuActions::Close);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -498,26 +506,33 @@ fn ConversationOptionsMenu(
|
||||
pub fn Conversations() -> Element {
|
||||
let mut room_id = use_signal(|| None::<RoomId>);
|
||||
|
||||
let on_menu_close = move |_| {
|
||||
room_id.set(None);
|
||||
};
|
||||
|
||||
let on_menu_join = move |_| async move {
|
||||
let rooms = STORE.read().rooms();
|
||||
if let Some(room_id) = room_id.read().to_owned() {
|
||||
if let Some(room) = rooms.get(&room_id) {}
|
||||
}
|
||||
};
|
||||
|
||||
let on_pressed_conversation = move |id: RoomId| {
|
||||
room_id.set(Some(id));
|
||||
};
|
||||
|
||||
let callbacks = use_coroutine(
|
||||
move |mut rx: UnboundedReceiver<ConversationOptionsMenuActions>| async move {
|
||||
while let Some(action) = rx.next().await {
|
||||
match action {
|
||||
ConversationOptionsMenuActions::Join(room_id) => {
|
||||
let rooms = STORE.read().rooms();
|
||||
if let Some(room) = rooms.get(&room_id) {
|
||||
room.join().await;
|
||||
}
|
||||
}
|
||||
ConversationOptionsMenuActions::Close => {
|
||||
room_id.set(None);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
let menu = match room_id.read().as_ref() {
|
||||
Some(room_id) => {
|
||||
let room_id = room_id.clone();
|
||||
rsx! {
|
||||
ConversationOptionsMenu { room_id, on_close: on_menu_close, on_join: on_menu_join }
|
||||
ConversationOptionsMenu { room_id, callbacks }
|
||||
}
|
||||
}
|
||||
None => VNode::empty(),
|
||||
|
@@ -15,7 +15,8 @@ macro_rules! transparent_icon {
|
||||
($name:ident, $icon:ident) => {
|
||||
pub fn $name() -> Element {
|
||||
rsx! {
|
||||
style { {STYLE_SHEET} },
|
||||
style { {STYLE_SHEET} }
|
||||
|
||||
Icon {
|
||||
class: ClassName::TRANSPARENT_ICON,
|
||||
icon: $icon,
|
||||
@@ -52,7 +53,7 @@ impl IconShape for LogoShape {
|
||||
|
||||
pub fn LogoIcon() -> Element {
|
||||
rsx! {
|
||||
style { {STYLE_SHEET} },
|
||||
style { {STYLE_SHEET} }
|
||||
|
||||
Icon {
|
||||
icon: LogoShape,
|
||||
@@ -133,14 +134,14 @@ impl IconShape for PyramidShape {
|
||||
L {_PYRAMID_EDGES_E1_X} {_PYRAMID_CENTRAL_EDGE_E2_Y} \
|
||||
M {_PYRAMID_EDGES_E1_X} {_PYRAMID_EDGES_E1_Y} \
|
||||
V {_PYRAMID_CENTRAL_EDGE_Y_LEN}",
|
||||
},
|
||||
}
|
||||
path {
|
||||
d: "\
|
||||
M {_PYRAMID_CENTRAL_EDGE_E2_X} {_PYRAMID_CENTRAL_EDGE_E2_Y} \
|
||||
V {central_edge_ratio_e2_y} \
|
||||
L {left_edge_ratio_e1_x} {no_central_edge_ratio_e1_y} \
|
||||
L {_PYRAMID_LEFT_EDGE_E2_X} {_PYRAMID_LEFT_EDGE_E2_Y} Z",
|
||||
},
|
||||
}
|
||||
path {
|
||||
d: "\
|
||||
M {_PYRAMID_CENTRAL_EDGE_E2_X} {_PYRAMID_CENTRAL_EDGE_E2_Y} \
|
||||
@@ -168,10 +169,11 @@ pub fn Pyramid(props: PyramidProps) -> Element {
|
||||
.unwrap_or(COLOR_TERNARY_100.to_string());
|
||||
|
||||
rsx! {
|
||||
style { {STYLE_SHEET} },
|
||||
style { {STYLE_SHEET} }
|
||||
|
||||
Icon {
|
||||
class: ClassName::PYRAMID_ICON,
|
||||
|
||||
icon: PyramidShape { ratio: props.ratio, color, progress_color },
|
||||
}
|
||||
}
|
||||
|
@@ -97,27 +97,6 @@ impl Clone for Box<dyn OnValidationError> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct TextInputHandler {
|
||||
state: Signal<TextInputState>,
|
||||
}
|
||||
|
||||
impl TextInputHandler {}
|
||||
|
||||
impl OnValidationError for TextInputHandler {
|
||||
fn reset(&mut self) {
|
||||
self.state.write().reset();
|
||||
}
|
||||
|
||||
fn invalidate(&mut self, helper_text: String) {
|
||||
self.state.write().invalidate(helper_text);
|
||||
}
|
||||
|
||||
fn box_clone(&self) -> Box<dyn OnValidationError> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct UrlInputHandler {
|
||||
state: Signal<TextInputState>,
|
||||
@@ -744,7 +723,7 @@ pub fn Login() -> Element {
|
||||
let confirm_password_classes_str = confirm_password_classes.join(" ");
|
||||
|
||||
rsx! {
|
||||
style { {STYLE_SHEET} },
|
||||
style { {STYLE_SHEET} }
|
||||
|
||||
div {
|
||||
class: "{classes_str}",
|
||||
@@ -756,73 +735,79 @@ pub fn Login() -> Element {
|
||||
random_avatar_future.restart()
|
||||
},
|
||||
|
||||
{avatar},
|
||||
},
|
||||
{avatar}
|
||||
}
|
||||
|
||||
div {
|
||||
class: ClassName::LOGIN_HOMESERVER,
|
||||
|
||||
TextInput {
|
||||
placeholder: "Homeserver URL",
|
||||
value: "{homeserver_url}",
|
||||
state: homeserver_url_state,
|
||||
oninput: on_input![data, homeserver_url],
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
div {
|
||||
class: ClassName::LOGIN_ID,
|
||||
|
||||
TextInput {
|
||||
placeholder: "{id_placeholder}",
|
||||
value: "{id}",
|
||||
state: id_state,
|
||||
oninput: on_input![data, id],
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
div {
|
||||
class: "{password_classes_str}",
|
||||
|
||||
PasswordTextInput {
|
||||
placeholder: "Password",
|
||||
value: "{password}",
|
||||
state: password_state,
|
||||
oninput: on_input![data, password],
|
||||
},
|
||||
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
div {
|
||||
class: "{confirm_password_classes_str}",
|
||||
|
||||
PasswordTextInput {
|
||||
placeholder: "Confirm Password",
|
||||
value: "{confirm_password}",
|
||||
state: confirm_password_state,
|
||||
oninput: on_input![data, confirm_password],
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
div {
|
||||
class: ClassName::LOGIN_SPINNER,
|
||||
|
||||
Spinner {
|
||||
animate: *spinner_animated.read(),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
div {
|
||||
class: ClassName::LOGIN_REGISTER_BUTTON,
|
||||
|
||||
RegisterButton {
|
||||
onclick: on_clicked_register,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
div {
|
||||
class: ClassName::LOGIN_LOGIN_BUTTON,
|
||||
|
||||
LoginButton {
|
||||
focus: true,
|
||||
onclick: on_clicked_login,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{rendered_modal},
|
||||
{rendered_modal}
|
||||
}
|
||||
}
|
||||
|
@@ -76,7 +76,7 @@ pub fn Modal(props: ModalProps) -> Element {
|
||||
Severity::Critical => ErrorButton,
|
||||
};
|
||||
|
||||
icon.as_ref().ok_or(VNode::empty());
|
||||
let _ = icon.as_ref().ok_or(VNode::empty());
|
||||
|
||||
rsx! {
|
||||
style { {STYLE_SHEET} }
|
||||
|
@@ -13,13 +13,14 @@ pub struct SpinnerProps {
|
||||
|
||||
pub fn Spinner(props: SpinnerProps) -> Element {
|
||||
rsx! {
|
||||
style { {STYLE_SHEET} },
|
||||
style { {STYLE_SHEET} }
|
||||
|
||||
div {
|
||||
class: ClassName::SPINNER,
|
||||
|
||||
Icon {
|
||||
class: if props.animate { "" } else { ClassName::PAUSED },
|
||||
|
||||
icon: LogoShape,
|
||||
}
|
||||
}
|
||||
|
@@ -10,7 +10,8 @@ pub fn Wallpaper(display_version: Option<bool>) -> Element {
|
||||
let version = display_version.map(|flag| if flag { Some(GIT_VERSION) } else { None });
|
||||
|
||||
rsx! {
|
||||
style { {STYLE_SHEET} },
|
||||
style { {STYLE_SHEET} }
|
||||
|
||||
div {
|
||||
class: ClassName::WALLPAPER,
|
||||
|
||||
@@ -20,7 +21,8 @@ pub fn Wallpaper(display_version: Option<bool>) -> Element {
|
||||
|
||||
div {
|
||||
class: ClassName::WALLPAPER_VERSION,
|
||||
{version},
|
||||
|
||||
{version}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -7,7 +7,7 @@ turf::style_sheet!("src/ui/layouts/login.scss");
|
||||
|
||||
pub fn Login() -> Element {
|
||||
rsx! {
|
||||
style { {STYLE_SHEET} },
|
||||
style { {STYLE_SHEET} }
|
||||
|
||||
Wallpaper {
|
||||
display_version: true
|
||||
|
@@ -33,7 +33,6 @@ pub struct Store {
|
||||
pub struct Room {
|
||||
store: RefCell<Store>,
|
||||
|
||||
#[allow(dead_code)]
|
||||
domain: Rc<dyn RoomStoreConsumerInterface>,
|
||||
}
|
||||
|
||||
@@ -57,6 +56,10 @@ impl Room {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn join(&self) {
|
||||
self.domain.join().await;
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn get_avatar(&self) -> Option<Avatar> {
|
||||
self.domain.avatar().await
|
||||
@@ -81,6 +84,11 @@ impl RoomStoreProviderInterface for Room {
|
||||
|
||||
fn on_new_member(&self, member: RoomMember) {
|
||||
let mut store = self.store.borrow_mut();
|
||||
|
||||
if member.is_account_user() {
|
||||
store.is_invited.set(false);
|
||||
}
|
||||
|
||||
store.members.write().push(member);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user