diff options
author | 2025-05-23 16:00:54 +0100 | |
---|---|---|
committer | 2025-05-23 16:00:54 +0100 | |
commit | eff7045e9f871c0ec6eb0401c77ab4209b36d636 (patch) | |
tree | bb5d9007f37ec0e76cdc511c937062f7249a3215 /src/lib.rs | |
parent | f14ac34129b05b7424fb0c002920c6bf40ad45ab (diff) | |
download | macaw-web-eff7045e9f871c0ec6eb0401c77ab4209b36d636.tar.gz macaw-web-eff7045e9f871c0ec6eb0401c77ab4209b36d636.tar.bz2 macaw-web-eff7045e9f871c0ec6eb0401c77ab4209b36d636.zip |
feat: subscription request badges
Diffstat (limited to 'src/lib.rs')
-rw-r--r-- | src/lib.rs | 36 |
1 files changed, 33 insertions, 3 deletions
@@ -649,6 +649,7 @@ fn Macaw( // TODO: timestamp incoming/outgoing subscription requests let (subscription_requests, set_subscription_requests)= signal(HashSet::<JID>::new()); provide_context(subscription_requests); + provide_context(set_subscription_requests); // TODO: get cached contacts on login before getting the updated contacts @@ -769,6 +770,8 @@ pub fn toggle_open(state: &mut Option<SidebarOpen>, open: SidebarOpen) -> bool { #[component] pub fn Sidebar() -> impl IntoView { + let requests: ReadSignal<HashSet<JID>> = use_context().expect("no pending subscriptions in context"); + // for what has been clicked open (in the background) let (open, set_open) = signal(None::<SidebarOpen>); // for what is just in the hovered state (not clicked to be pinned open yet necessarily) @@ -795,7 +798,21 @@ pub fn Sidebar() -> impl IntoView { }) }> <div class="dock-pill"></div> - <img src="/assets/caw.png" /> + <div class="dock-icon"> + <div class="icon-with-badge"> + <img src="/assets/caw.png" /> + {move || { + let len = requests.read().len(); + if len > 0 { + view! { + <div class="badge">{len}</div> + }.into_any() + } else { + view! {}.into_any() + } + }} + </div> + </div> </div> <div class="chats-tab dock-item" class:focused=move || *open.read() == Some(SidebarOpen::Chats) class:hovering=move || *hovered.read() == Some(SidebarOpen::Chats) on:mouseenter=move |_| { @@ -2166,6 +2183,8 @@ fn NewChatWidget(set_open_new_chat: WriteSignal<bool>) -> impl IntoView { #[component] fn RosterList() -> impl IntoView { + let requests: ReadSignal<HashSet<JID>> = use_context().expect("no pending subscriptions in context"); + let roster: Store<Roster> = use_context().expect("no roster in context"); let (open_add_contact, set_open_add_contact) = signal(false); @@ -2176,6 +2195,15 @@ fn RosterList() -> impl IntoView { <h2>Roster</h2> <div class="add-contact header-icon" class:open=open_add_contact> <IconComponent icon=Icon::AddContact24 on:click=move |_| set_open_add_contact.update(|state| *state = !*state)/> + {move || { + if !requests.read().is_empty() { + view! { + <div class="badge"></div> + }.into_any() + } else { + view! {}.into_any() + } + }} </div> </div> {move || { @@ -2211,6 +2239,7 @@ pub enum AddContactError { #[component] fn AddContact() -> impl IntoView { let requests: ReadSignal<HashSet<JID>> = use_context().expect("no pending subscriptions in context"); + let set_requests: WriteSignal<HashSet<JID>> = use_context().expect("no pending subscriptions write signal in context"); let roster: Store<Roster> = use_context().expect("no roster in context"); let jid = RwSignal::new("".to_string()); @@ -2306,7 +2335,8 @@ fn AddContact() -> impl IntoView { let jid = jid.clone(); async move { // TODO: error - client.unsubscribe_contact(jid).await; + client.unsubscribe_contact(jid.clone()).await; + set_requests.write().remove(&jid); } }); @@ -2352,7 +2382,7 @@ fn AddContact() -> impl IntoView { let jid_string = move || request.to_string(); view! { <div class="jid-with-button"><div class="jid">{jid_string}</div> - <div><div class="button" on:click=move |_| { accept_friend_request.dispatch(request2.clone()); } >Accept</div><div class="button" on:click=move |_| { reject_friend_request.dispatch(request3.clone()); } >Accept</div></div></div> + <div><div class="button" on:click=move |_| { accept_friend_request.dispatch(request2.clone()); } >Accept</div><div class="button" on:click=move |_| { reject_friend_request.dispatch(request3.clone()); } >Reject</div></div></div> } } </For> |