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