2 Commits

Author SHA1 Message Date
aaafa91cbe ⬆️ Bump turf version (0.8.0 -> 0.9.3) 2024-08-21 23:29:35 +02:00
9a5f7ae504 ⬆️ Use of Dioxus main branch instead of 0.5 release 2024-08-21 23:29:33 +02:00
10 changed files with 319 additions and 188 deletions

View File

@@ -40,33 +40,38 @@ tracing = "0.1.40"
tracing-forest = "0.1.6" tracing-forest = "0.1.6"
# SCSS -> CSS + usage in rust code # SCSS -> CSS + usage in rust code
turf = "0.8.0" turf = "0.9.3"
# Dioxus # Dioxus
dioxus = { version = "0.5", default-features = false } # dioxus-free-icons = { version = "0.8", features = ["ionicons", "font-awesome-solid"] }
dioxus-free-icons = { version = "0.8", features = ["ionicons", "font-awesome-solid"] } dioxus-free-icons = { git = "https://github.com/ASR-ASU/dioxus-free-icons.git", branch = "asr/dioxus-0.6", features = ["ionicons", "font-awesome-solid"] }
modx = "0.1.2" modx = "0.1.2"
[patch.crates-io] # Matrix rich text editor
dioxus = { git = "https://github.com/DioxusLabs/dioxus.git" } wysiwyg = { path = "../matrix.org/matrix-rich-text-editor/crates/wysiwyg/" }
[target.'cfg(target_family = "wasm")'.dependencies] [target.'cfg(target_family = "wasm")'.dependencies]
# Logging/tracing # Logging/tracing
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
tracing-web = "0.1.3" tracing-web = "0.1.3"
# Dioxus # Dioxus
dioxus = { features = ["web"] } dioxus = { git = "https://github.com/DioxusLabs/dioxus.git", branch = "main", features = ["web"] }
web-sys = "0.3.69" web-sys = "0.3.69"
# Matrix # Matrix
matrix-sdk = { git = "https://github.com/matrix-org/matrix-rust-sdk.git", default-features = false, features = ["rustls-tls", "js"] } matrix-sdk = { git = "https://github.com/matrix-org/matrix-rust-sdk.git", default-features = false, features = ["rustls-tls", "js"] }
[target.'cfg(not(target_family = "wasm"))'.dependencies] [target.'cfg(not(target_family = "wasm"))'.dependencies]
# Utils # Utils
time = "0.3.36" time = "0.3.36"
# Logging/tracing # Logging/tracing
tracing-subscriber = { version = "0.3.18", features = ["env-filter", "time"] } tracing-subscriber = { version = "0.3.18", features = ["env-filter", "time"] }
# Dioxus # Dioxus
dioxus = { features = ["desktop"] } dioxus = { git = "https://github.com/DioxusLabs/dioxus.git", branch = "main", features = ["desktop"] }
# Matrix # Matrix
matrix-sdk = { git = "https://github.com/matrix-org/matrix-rust-sdk.git", default-features = false, features = ["rustls-tls"] } matrix-sdk = { git = "https://github.com/matrix-org/matrix-rust-sdk.git", default-features = false, features = ["rustls-tls"] }

View File

@@ -9,7 +9,7 @@ use dioxus::prelude::Task;
use matrix_sdk::{ use matrix_sdk::{
config::SyncSettings, config::SyncSettings,
event_handler::Ctx, event_handler::Ctx,
media::{MediaFormat, MediaRequest, MediaThumbnailSize}, media::{MediaFormat, MediaRequest, MediaThumbnailSettings, MediaThumbnailSize},
room::{ParentSpace, Room}, room::{ParentSpace, Room},
ruma::{ ruma::{
api::client::media::get_content_thumbnail::v3::Method, api::client::media::get_content_thumbnail::v3::Method,
@@ -448,10 +448,13 @@ impl Client {
async fn on_room_avatar_event(room: &Room, senders: &Ctx<Senders>) { async fn on_room_avatar_event(room: &Room, senders: &Ctx<Senders>) {
let room_id = room.room_id(); let room_id = room.room_id();
let avatar = match room let avatar = match room
.avatar(MediaFormat::Thumbnail(MediaThumbnailSize { .avatar(MediaFormat::Thumbnail(MediaThumbnailSettings {
size: MediaThumbnailSize {
method: Method::Scale, method: Method::Scale,
width: uint!(256), width: uint!(256),
height: uint!(256), height: uint!(256),
},
animated: false,
})) }))
.await .await
{ {
@@ -668,10 +671,13 @@ impl Client {
match client match client
.account() .account()
.get_avatar(MediaFormat::Thumbnail(MediaThumbnailSize { .get_avatar(MediaFormat::Thumbnail(MediaThumbnailSettings {
size: MediaThumbnailSize {
method: Method::Scale, method: Method::Scale,
width: uint!(256), width: uint!(256),
height: uint!(256), height: uint!(256),
},
animated: false,
})) }))
.await .await
{ {
@@ -685,10 +691,13 @@ impl Client {
if let Some(room) = client.get_room(room_id) { if let Some(room) = client.get_room(room_id) {
match room match room
.avatar(MediaFormat::Thumbnail(MediaThumbnailSize { .avatar(MediaFormat::Thumbnail(MediaThumbnailSettings {
size: MediaThumbnailSize {
method: Method::Scale, method: Method::Scale,
width: uint!(256), width: uint!(256),
height: uint!(256), height: uint!(256),
},
animated: false,
})) }))
.await .await
{ {
@@ -709,10 +718,13 @@ impl Client {
let request = MediaRequest { let request = MediaRequest {
source: MediaSource::Plain(media_url), source: MediaSource::Plain(media_url),
format: MediaFormat::Thumbnail(MediaThumbnailSize { format: MediaFormat::Thumbnail(MediaThumbnailSettings {
size: MediaThumbnailSize {
method: Method::Scale, method: Method::Scale,
width: uint!(256), width: uint!(256),
height: uint!(256), height: uint!(256),
},
animated: false,
}), }),
}; };
@@ -739,10 +751,13 @@ impl Client {
Ok(room_member) => { Ok(room_member) => {
if let Some(room_member) = room_member { if let Some(room_member) = room_member {
let res = match room_member let res = match room_member
.avatar(MediaFormat::Thumbnail(MediaThumbnailSize { .avatar(MediaFormat::Thumbnail(MediaThumbnailSettings {
size: MediaThumbnailSize {
method: Method::Scale, method: Method::Scale,
width: uint!(256), width: uint!(256),
height: uint!(256), height: uint!(256),
},
animated: false,
})) }))
.await .await
{ {

View File

@@ -21,19 +21,14 @@ turf::style_sheet!("src/ui/components/conversations.scss");
#[component] #[component]
fn AccountAvatar(content: Option<Vec<u8>>, class_name: Option<String>) -> Element { fn AccountAvatar(content: Option<Vec<u8>>, class_name: Option<String>) -> Element {
match content {
Some(content) => {
let encoded = general_purpose::STANDARD.encode(content);
rsx! { rsx! {
if let Some(content) = content {
div { div {
class: class_name, class: class_name,
background_image: format!("url(data:image/jpeg;base64,{encoded})") background_image: format!("url(data:image/jpeg;base64,{})", general_purpose::STANDARD.encode(content))
} }
} }
} }
// TODO: Manage acount without avatar
None => None,
}
} }
#[component] #[component]
@@ -54,11 +49,11 @@ fn PresenceState(state: Option<DomainPresenceState>, class_name: Option<String>)
rsx! { rsx! {
div { div {
class: classes, class: classes,
LogoIcon {}, LogoIcon {}
} }
} }
} }
None => None, None => VNode::empty(),
} }
} }
@@ -70,12 +65,12 @@ fn DisplayName(display_name: Option<String>, class_name: Option<String>) -> Elem
div { div {
class: class_name, class: class_name,
p { p {
{display_name}, {display_name}
} }
} }
} }
} }
None => None, None => VNode::empty(),
} }
} }
@@ -137,37 +132,35 @@ pub fn Account() -> Element {
}); });
rsx! { rsx! {
style { {STYLE_SHEET} },
div { div {
class: ClassName::ACCOUNT, class: ClassName::ACCOUNT,
{avatar}, {avatar}
{presence_state}, {presence_state}
{display_name}, {display_name}
{status}, {status}
div { div {
class: ClassName::ACCOUNT_SPACES, class: ClassName::ACCOUNT_SPACES,
Button { Button {
SpacesIcon {}, SpacesIcon {}
}
} }
},
div { div {
class: ClassName::ACCOUNT_CHAT, class: ClassName::ACCOUNT_CHAT,
Button { Button {
ChatsIcon {}, ChatsIcon {}
}
} }
},
div { div {
class: ClassName::ACCOUNT_ROOM, class: ClassName::ACCOUNT_ROOM,
Button { Button {
RoomsIcon {}, RoomsIcon {}
}
} }
},
} }
} }
} }
@@ -175,8 +168,8 @@ pub fn Account() -> Element {
#[component] #[component]
pub fn ConversationAvatar( pub fn ConversationAvatar(
room_id: RoomId, room_id: RoomId,
on_selected: EventHandler<RoomId>, on_selected: Option<EventHandler<RoomId>>,
on_pressed: EventHandler<RoomId>, on_pressed: Option<EventHandler<RoomId>>,
) -> Element { ) -> Element {
let long_press_duration = Duration::from_millis(500); let long_press_duration = Duration::from_millis(500);
@@ -185,7 +178,7 @@ pub fn ConversationAvatar(
let room_id = Rc::new(room_id); let room_id = Rc::new(room_id);
let room_name = room.name(); let room_name = room.name();
let selected_room_id = use_context::<Signal<Option<RoomId>>>(); let selected_room_id = use_signal(|| None::<RoomId>);
let invited_badge = if room.is_invited() { let invited_badge = if room.is_invited() {
rsx! { rsx! {
@@ -193,12 +186,12 @@ pub fn ConversationAvatar(
class: ClassName::CONVERSATION_AVATAR_INVITED_BADGE, class: ClassName::CONVERSATION_AVATAR_INVITED_BADGE,
p { p {
"Invited", "Invited"
} }
} }
} }
} else { } else {
None VNode::empty()
}; };
let is_selected = match selected_room_id.read().as_ref() { let is_selected = match selected_room_id.read().as_ref() {
@@ -206,7 +199,6 @@ pub fn ConversationAvatar(
None => false, None => false,
}; };
// let avatar = if let Some(Some(content)) = &*avatar.read() {
let avatar = if let Some(content) = room.avatar() { let avatar = if let Some(content) = room.avatar() {
let encoded = general_purpose::STANDARD.encode(content); let encoded = general_purpose::STANDARD.encode(content);
rsx! { rsx! {
@@ -230,7 +222,7 @@ pub fn ConversationAvatar(
div { div {
class: ClassName::CONVERSATION_AVATAR_IMAGE, class: ClassName::CONVERSATION_AVATAR_IMAGE,
{placeholder}, {placeholder}
} }
} }
}; };
@@ -244,12 +236,12 @@ pub fn ConversationAvatar(
let on_press = { let on_press = {
let room_id = room_id.clone(); let room_id = room_id.clone();
move || { move || {
on_selected.call(room_id.as_ref().clone()); on_selected.map(|c| c.call(room_id.as_ref().clone()));
} }
}; };
let on_long_press = move || { let on_long_press = move || {
on_pressed.call(room_id.as_ref().clone()); on_pressed.map(|c| c.call(room_id.as_ref().clone()));
}; };
let long_press_hook = use_long_press(long_press_duration, on_press, on_long_press); let long_press_hook = use_long_press(long_press_duration, on_press, on_long_press);
@@ -302,7 +294,7 @@ pub fn ConversationsCarousel(
onscroll: move |_| { onscroll: move |_| {
// Catch scrolling events. // Catch scrolling events.
}, },
{rendered_avatars}, {rendered_avatars}
} }
} }
} }
@@ -367,8 +359,6 @@ pub fn Space(id: Option<SpaceId>, on_pressed_conversation: EventHandler<RoomId>)
let classes_str = space_classes.join(" "); let classes_str = space_classes.join(" ");
rsx! { rsx! {
style { {STYLE_SHEET} },
div { div {
class: "{classes_str}", class: "{classes_str}",
@@ -382,17 +372,17 @@ pub fn Space(id: Option<SpaceId>, on_pressed_conversation: EventHandler<RoomId>)
p { p {
{name} {name}
} }
}, }
ConversationsCarousel { ConversationsCarousel {
on_selected_conversation, on_selected_conversation,
on_pressed_conversation, on_pressed_conversation,
}, }
div { div {
class: ClassName::SPACE_CONVERSATION_NAME, class: ClassName::SPACE_CONVERSATION_NAME,
p { p {
{selected_room_name}, {selected_room_name}
}
} }
},
} }
} }
} }
@@ -412,19 +402,24 @@ pub fn Spaces(on_pressed_conversation: EventHandler<RoomId>) -> Element {
div { div {
class: ClassName::SPACES, class: ClassName::SPACES,
{rendered_spaces}, {rendered_spaces}
Space { on_pressed_conversation }, Space { on_pressed_conversation }
} }
} }
} }
#[component]
pub fn Search() -> Element { pub fn Search() -> Element {
rsx! { rsx! {
div { div {
class: ClassName::SEARCH, class: ClassName::SEARCH,
div {
class: ClassName::SEARCH_TEXT,
TextInput {} TextInput {}
}
div { div {
class: ClassName::SEARCH_BUTTON, class: ClassName::SEARCH_BUTTON,
@@ -437,7 +432,15 @@ pub fn Search() -> Element {
} }
#[component] #[component]
fn ConversationOptionsMenu(room_id: RoomId, on_close: EventHandler) -> Element { fn ConversationOptionsMenu(
room_id: RoomId,
on_close: EventHandler,
on_join: EventHandler,
) -> Element {
let room = STORE.read().rooms().get(&room_id).unwrap().signal();
let topic = room.topic().unwrap_or("<No topic set>".to_string());
rsx! { rsx! {
div { div {
class: ClassName::CONVERSATION_OPTIONS_MENU, class: ClassName::CONVERSATION_OPTIONS_MENU,
@@ -447,31 +450,44 @@ fn ConversationOptionsMenu(room_id: RoomId, on_close: EventHandler) -> Element {
div { div {
class: ClassName::CONVERSATION_OPTIONS_MENU_INNER_AVATAR, class: ClassName::CONVERSATION_OPTIONS_MENU_INNER_AVATAR,
ConversationAvatar { room_id }
} }
div { div {
class: ClassName::CONVERSATION_OPTIONS_MENU_INNER_NAME, class: ClassName::CONVERSATION_OPTIONS_MENU_INNER_NAME,
p {
{room.name()}
}
} }
div { div {
class: ClassName::CONVERSATION_OPTIONS_MENU_INNER_TOPIC, class: ClassName::CONVERSATION_OPTIONS_MENU_INNER_TOPIC,
p {
{topic}
}
} }
div { div {
class: ClassName::CONVERSATION_OPTIONS_MENU_INNER_CONFIG, class: ClassName::CONVERSATION_OPTIONS_MENU_INNER_CONFIG,
p {
"Coming soon..."
}
} }
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 |_| on_close(())
} }
} }
div { div {
class: ClassName::CONVERSATION_OPTIONS_MENU_INNER_JOIN_BUTTON, class: ClassName::CONVERSATION_OPTIONS_MENU_INNER_JOIN_BUTTON,
JoinButton { JoinButton {
onclick: move |_| on_close(()), onclick: move |_| {
on_join(());
on_close(());
}
} }
} }
} }
@@ -480,37 +496,54 @@ fn ConversationOptionsMenu(room_id: RoomId, on_close: EventHandler) -> Element {
} }
pub fn Conversations() -> Element { pub fn Conversations() -> Element {
let mut conversation_options_menu = use_signal(|| None::<Element>); let mut room_id = use_signal(|| None::<RoomId>);
let on_conversation_options_menu_close = move |_| { let on_menu_close = move |_| {
conversation_options_menu.set(None); room_id.set(None);
}; };
let on_pressed_conversation = move |room_id: RoomId| { let on_menu_join = move |_| async move {
conversation_options_menu.set(Some(rsx! { ConversationOptionsMenu { room_id, on_close: on_conversation_options_menu_close } })); 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 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 }
}
}
None => VNode::empty(),
}; };
rsx! { rsx! {
style { {STYLE_SHEET} }, style { {STYLE_SHEET} }
div { div {
class: ClassName::CONVERSATIONS, class: ClassName::CONVERSATIONS,
div { div {
class: ClassName::CONVERSATIONS_ACCOUNT, class: ClassName::CONVERSATIONS_ACCOUNT,
Account {}, Account {}
}, }
div { div {
class: ClassName::CONVERSATIONS_SPACES, class: ClassName::CONVERSATIONS_SPACES,
Spaces { on_pressed_conversation }, Spaces { on_pressed_conversation }
}, }
div { div {
class: ClassName::CONVERSATIONS_SEARCH, class: ClassName::CONVERSATIONS_SEARCH,
Search {}, Search {}
}, }
}, }
{conversation_options_menu} {menu}
} }
} }

View File

@@ -268,6 +268,11 @@
display: flex; display: flex;
gap: 5%; gap: 5%;
&__text {
height: 100%;
width: 100%;
}
&__button { &__button {
@include button-class(); @include button-class();
@@ -313,6 +318,24 @@
} }
} }
%base-helper-text {
margin: 0;
margin-top: 0.3vh;
font-size: 1.2vh;
// TODO: Set color used for text in _base.scss file
color: get-color(greyscale, 90);
p {
margin: 0;
&.invalid {
color: get-color(critical, 100);
}
}
}
.conversation-options-menu { .conversation-options-menu {
width: 100%; width: 100%;
height: 100%; height: 100%;
@@ -355,23 +378,50 @@
width: 100%; width: 100%;
aspect-ratio: 1; aspect-ratio: 1;
background-color: green;
} }
&__name { &__name {
grid-area: name; grid-area: name;
background-color: orange;
// TODO: Merge with &__display-name
display: flex;
align-items: center;
justify-content: center;
p {
font-size: 2.5vh;
margin: 0;
text-align: center;
}
} }
&__topic { &__topic {
grid-area: topic; grid-area: topic;
background-color: aqua;
// TODO: Merge with &__display-name
display: flex;
align-items: center;
justify-content: center;
@extend %base-helper-text;
p {
font-size: 2vh;
margin: 0;
text-align: center;
}
} }
&__config { &__config {
grid-area: config; grid-area: config;
background-color: purple;
// TODO: Merge with &__display-name
display: flex;
align-items: center;
justify-content: center;
border: $border-thin;
border-color: get-color(ternary, 90);
border-radius: $border-radius;
} }
button { button {

View File

@@ -76,10 +76,10 @@ pub fn Modal(props: ModalProps) -> Element {
Severity::Critical => ErrorButton, Severity::Critical => ErrorButton,
}; };
icon.as_ref()?; icon.as_ref().ok_or(VNode::empty());
rsx! { rsx! {
style { {STYLE_SHEET} }, style { {STYLE_SHEET} }
div { div {
class: ClassName::MODAL, class: ClassName::MODAL,
@@ -90,17 +90,17 @@ pub fn Modal(props: ModalProps) -> Element {
div { div {
class: ClassName::MODAL_CONTENT_ICON, class: ClassName::MODAL_CONTENT_ICON,
{icon} {icon}
}, }
div { div {
class: ClassName::MODAL_CONTENT_TITLE, class: ClassName::MODAL_CONTENT_TITLE,
{props.title}, {props.title}
}, }
div { div {
class: ClassName::MODAL_CONTENT_MSG, class: ClassName::MODAL_CONTENT_MSG,
{props.children}, {props.children}
}, }
div { div {
class: ClassName::MODAL_CONTENT_BUTTONS, class: ClassName::MODAL_CONTENT_BUTTONS,
@@ -109,10 +109,10 @@ pub fn Modal(props: ModalProps) -> Element {
if let Some(cb) = &props.on_confirm { if let Some(cb) = &props.on_confirm {
cb.call(evt); cb.call(evt);
} }
}, }
}, }
}, }
}, }
}, }
} }
} }

View File

@@ -67,7 +67,7 @@ pub fn TextInput(props: InputProps<TextInputState>) -> Element {
let input_classes_str = [ClassName::TEXT_INPUT_INPUT, criticity_class].join(" "); let input_classes_str = [ClassName::TEXT_INPUT_INPUT, criticity_class].join(" ");
rsx! { rsx! {
style { {STYLE_SHEET} }, style { {STYLE_SHEET} }
div { div {
class: ClassName::TEXT_INPUT, class: ClassName::TEXT_INPUT,
@@ -83,7 +83,7 @@ pub fn TextInput(props: InputProps<TextInputState>) -> Element {
cb.call(evt); cb.call(evt);
} }
}, },
}, }
div { div {
class: ClassName::TEXT_INPUT_HELPER_TEXT, class: ClassName::TEXT_INPUT_HELPER_TEXT,
@@ -159,7 +159,7 @@ pub fn PasswordTextInput(props: InputProps<PasswordInputState>) -> Element {
let input_classes = [ClassName::PASSWORD_TEXT_INPUT_INPUT, criticity_class].join(" "); let input_classes = [ClassName::PASSWORD_TEXT_INPUT_INPUT, criticity_class].join(" ");
rsx! { rsx! {
style { {STYLE_SHEET} }, style { {STYLE_SHEET} }
div { div {
class: "{text_input_classes}", class: "{text_input_classes}",
@@ -175,7 +175,7 @@ pub fn PasswordTextInput(props: InputProps<PasswordInputState>) -> Element {
cb.call(evt); cb.call(evt);
} }
}, },
}, }
if let Some(score) = score { if let Some(score) = score {
div { div {
@@ -184,7 +184,7 @@ pub fn PasswordTextInput(props: InputProps<PasswordInputState>) -> Element {
ratio: score, ratio: score,
} }
} }
}, }
div { div {
class: ClassName::PASSWORD_TEXT_INPUT_SHOW_TOGGLE, class: ClassName::PASSWORD_TEXT_INPUT_SHOW_TOGGLE,
@@ -203,7 +203,7 @@ pub fn PasswordTextInput(props: InputProps<PasswordInputState>) -> Element {
icon: IoEye, icon: IoEye,
} }
} }
}, }
div { div {
class: ClassName::PASSWORD_TEXT_INPUT_HELPER_TEXT, class: ClassName::PASSWORD_TEXT_INPUT_HELPER_TEXT,
@@ -212,7 +212,7 @@ pub fn PasswordTextInput(props: InputProps<PasswordInputState>) -> Element {
class: criticity_class, class: criticity_class,
{helper_text} {helper_text}
} }
}, }
} }
} }
} }

View File

@@ -1,4 +1,4 @@
@import "../_base.scss" @import "../_base.scss";
%base-text-input { %base-text-input {
$horizontal-padding: 1vw; $horizontal-padding: 1vw;

View File

@@ -14,20 +14,20 @@ pub fn use_long_press(
on_long_press: impl FnMut() + 'static, on_long_press: impl FnMut() + 'static,
) -> UseLongPress { ) -> UseLongPress {
let on_press = std::rc::Rc::new(RefCell::new(on_press)); let on_press = std::rc::Rc::new(RefCell::new(on_press));
let on_press_cb = use_callback(move || { let on_press_cb = use_callback(move |_| {
let mut on_press = on_press.as_ref().borrow_mut(); let mut on_press = on_press.as_ref().borrow_mut();
on_press(); on_press();
}); });
let on_long_press = std::rc::Rc::new(RefCell::new(on_long_press)); let on_long_press = std::rc::Rc::new(RefCell::new(on_long_press));
let on_long_press_cb = use_callback(move || { let on_long_press_cb = use_callback(move |_| {
let mut on_long_press = on_long_press.as_ref().borrow_mut(); let mut on_long_press = on_long_press.as_ref().borrow_mut();
on_long_press(); on_long_press();
}); });
let mut timer = use_future(move || async move { let mut timer = use_future(move || async move {
task::sleep(duration).await; task::sleep(duration).await;
on_long_press_cb.call(); on_long_press_cb.call(());
}); });
timer.cancel(); timer.cancel();
@@ -39,7 +39,7 @@ pub fn use_long_press(
let selection_end_cb = move |_: Event<PlatformEventData>| { let selection_end_cb = move |_: Event<PlatformEventData>| {
if !timer.finished() { if !timer.finished() {
timer.cancel(); timer.cancel();
on_press_cb.call(); on_press_cb.call(());
} }
}; };

View File

@@ -1,15 +1,19 @@
use std::rc::Rc; use std::{collections::HashSet, rc::Rc};
use base64::{engine::general_purpose, Engine as _};
use dioxus::prelude::*; use dioxus::prelude::*;
use futures::join; use futures::join;
use tracing::warn; use tracing::warn;
use crate::ui::{ use crate::{
domain::model::room::RoomId,
ui::{
components::{ components::{
chat_panel::ChatPanel, conversations::Conversations as ConversationsComponent, chat_panel::ChatPanel, conversations::Conversations as ConversationsComponent,
wallpaper::Wallpaper, wallpaper::Wallpaper,
}, },
STORE, STORE,
},
}; };
turf::style_sheet!("src/ui/layouts/conversations.scss"); turf::style_sheet!("src/ui/layouts/conversations.scss");
@@ -66,7 +70,7 @@ fn LayoutSmall() -> Element {
let inner = rsx! { let inner = rsx! {
div { div {
class: ClassName::CONVERSATIONS_VIEW_SMALL_PANEL_INNER, class: ClassName::CONVERSATIONS_VIEW_SMALL_PANEL_INNER,
ChatPanel { name: format!("CHAT {room_name_repr}") }, ChatPanel { name: format!("CHAT {room_name_repr}") }
} }
}; };
@@ -88,7 +92,7 @@ fn LayoutSmall() -> Element {
} }
}; };
if let Some(panel) = panel { if let Ok(panel) = panel {
conversation_panels.push(panel); conversation_panels.push(panel);
} }
} else { } else {
@@ -97,7 +101,7 @@ fn LayoutSmall() -> Element {
} }
rsx! { rsx! {
style { {STYLE_SHEET} }, style { {STYLE_SHEET} }
div { div {
class: ClassName::CONVERSATIONS_VIEW_SMALL, class: ClassName::CONVERSATIONS_VIEW_SMALL,
@@ -133,9 +137,9 @@ fn LayoutSmall() -> Element {
div { div {
class: ClassName::CONVERSATIONS_VIEW_SMALL_CONVERSATIONS_PANEL_INNER, class: ClassName::CONVERSATIONS_VIEW_SMALL_CONVERSATIONS_PANEL_INNER,
ConversationsComponent {}, ConversationsComponent {}
}, }
}, }
{conversation_panels.iter()} {conversation_panels.iter()}
@@ -164,33 +168,33 @@ fn LayoutBig() -> Element {
is_first = false; is_first = false;
rsx! { rsx! {
div { div {
class: ClassName::CONVERSATIONS_VIEW_BIG_CONVERSATION_PANELS_PANEL, class: ClassName::CONVERSATIONS_VIEW_BIG_CONVERSATIONS_PANELS_PANEL,
onmounted: move |cx| async move { onmounted: move |cx| async move {
let data = cx.data(); let data = cx.data();
let _ = data.as_ref().scroll_to(ScrollBehavior::Smooth).await; let _ = data.as_ref().scroll_to(ScrollBehavior::Smooth).await;
first_div.set(Some(data)); first_div.set(Some(data));
}, },
ChatPanel { name: room_name_repr }, ChatPanel { name: room_name_repr }
} }
} }
} else if displayed_room_ids_it.peek().is_none() { } else if displayed_room_ids_it.peek().is_none() {
rsx! { rsx! {
div { div {
class: ClassName::CONVERSATIONS_VIEW_BIG_CONVERSATION_PANELS_PANEL, class: ClassName::CONVERSATIONS_VIEW_BIG_CONVERSATIONS_PANELS_PANEL,
onmounted: move |cx: Event<MountedData>| last_div.set(Some(cx.data())), onmounted: move |cx: Event<MountedData>| last_div.set(Some(cx.data())),
ChatPanel { name: room_name_repr }, ChatPanel { name: room_name_repr }
} }
} }
} else { } else {
rsx! { rsx! {
div { div {
class: ClassName::CONVERSATIONS_VIEW_BIG_CONVERSATION_PANELS_PANEL, class: ClassName::CONVERSATIONS_VIEW_BIG_CONVERSATIONS_PANELS_PANEL,
ChatPanel { name: room_name_repr }, ChatPanel { name: room_name_repr }
} }
} }
}; };
if let Some(panel) = panel { if let Ok(panel) = panel {
conversation_panels.push(panel); conversation_panels.push(panel);
} }
} else { } else {
@@ -199,7 +203,7 @@ fn LayoutBig() -> Element {
} }
rsx! { rsx! {
style { {STYLE_SHEET} }, style { {STYLE_SHEET} }
div { div {
class: ClassName::CONVERSATIONS_VIEW_BIG, class: ClassName::CONVERSATIONS_VIEW_BIG,
@@ -207,11 +211,16 @@ fn LayoutBig() -> Element {
div { div {
class: ClassName::CONVERSATIONS_VIEW_BIG_CONVERSATIONS_PANEL, class: ClassName::CONVERSATIONS_VIEW_BIG_CONVERSATIONS_PANEL,
ConversationsComponent {}, ConversationsComponent {}
}, }
div { div {
class: ClassName::CONVERSATIONS_VIEW_BIG_CONVERSATION_PANELS, class: ClassName::CONVERSATIONS_VIEW_BIG_CONVERSATIONS,
div {
class: ClassName::CONVERSATIONS_VIEW_BIG_CONVERSATIONS_PANELS,
onmounted: move |cx| async move { onmounted: move |cx| async move {
let data = cx.data(); let data = cx.data();
@@ -239,8 +248,8 @@ fn LayoutBig() -> Element {
div { div {
class: ClassName::CONVERSATIONS_VIEW_TAIL, class: ClassName::CONVERSATIONS_VIEW_TAIL,
} }
}
}, }
} }
} }
} }
@@ -249,29 +258,29 @@ pub fn Conversations() -> Element {
let mut layout = use_signal(|| None::<VNode>); let mut layout = use_signal(|| None::<VNode>);
rsx! { rsx! {
style { {STYLE_SHEET} }, style { {STYLE_SHEET} }
Wallpaper { Wallpaper {
display_version: true display_version: true
}, }
div { div {
class: ClassName::CONVERSATIONS_VIEW, class: ClassName::CONVERSATIONS_VIEW,
onresized: move |cx| { onresize: move |cx| {
let data = cx.data(); let data = cx.data();
let mut use_big_layout = false; let mut use_big_layout = false;
if let Ok(size) = data.get_border_box_size() { if let Ok(size) = data.get_border_box_size() {
if let Some(size) = size.first() {
// Use LayoutBig if the layout can contain 2 panels side by side // Use LayoutBig if the layout can contain 2 panels side by side
let component_width = size.height * INNER_PANEL_HEIGHT_RATIO * ASPECT_RATIO; let component_width = size.height * INNER_PANEL_HEIGHT_RATIO * ASPECT_RATIO;
let breakpoint_width = component_width * 2_f64; let breakpoint_width = component_width * 2_f64;
use_big_layout = size.width > breakpoint_width; use_big_layout = size.width > breakpoint_width;
} }
}
layout.set(rsx! { if use_big_layout { LayoutBig {} } else { LayoutSmall {} }}); // let layout_result = rsx! { if use_big_layout { LayoutBig {} } else { LayoutSmall {} }};
let layout_result = rsx! { LayoutBig {} };
layout.set(Some(layout_result.unwrap()));
}, },
{layout} {layout}

View File

@@ -110,11 +110,29 @@ $inner-panel-height-ratio: 0.95;
aspect-ratio: $aspect-ratio; aspect-ratio: $aspect-ratio;
} }
&__conversation-panels { &__conversations {
height: $content-height; height: $content-height;
min-width: 64px;
flex-grow: 1; flex-grow: 1;
display: flex;
flex-direction: column;
gap: $gap;
&__tabs-bar {
height: 5%;
width: 100%;
flex-grow: 0;
// overflow: scroll;
// scrollbar-width: none;
}
&__panels {
flex-grow: 1;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
overflow-x: scroll; overflow-x: scroll;
@@ -135,4 +153,5 @@ $inner-panel-height-ratio: 0.95;
} }
} }
} }
}
} }