summaryrefslogblamecommitdiffstats
path: root/src/components/personal_status.rs
blob: 8439756a52f1e1333552d5e0b07e1998a803b6e1 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13












                                                                                                                                                                                                      




                                                                                          
                                                             







                                             
                                                                             




















































































































































                                                                                                                                                                               
use filamento::{presence::{Offline, Online, PresenceType, Show}, user::{User, UserStoreFields}};
use leptos::{html, prelude::*};
use reactive_stores::{ArcStore, Store};
use tracing::{debug, error};

use crate::{client::Client, components::{avatar::AvatarWithPresence, overlay::Overlay}, user::{get_name, MacawUser}, user_presences::UserPresences, views::{macaw::settings::SettingsPage, AppState}};

#[component]
pub fn PersonalStatus() -> impl IntoView {
    let user: LocalResource<MacawUser> = use_context().expect("no local user in context");

    let (open, set_open) = signal(false);
    move || if let Some(user) = user.get() {
        view! {
            <div class="dock-item" class:focused=move || *open.read()  on:click=move |_| {
                debug!("set open to true");
                set_open.update(|state| *state = !*state)
            }>
                <AvatarWithPresence user=user.get().into() />
                <div class="dock-pill"></div>
            </div>
            {move || {
                let open = open.get();
                debug!("open = {:?}", open);
                if open {
                view! {
                    <Overlay set_open>
                        <PersonalStatusMenu user=user.get().into() set_open/>
                    </Overlay>
                }.into_any()
            } else {
                view! {}.into_any()
            }}}
        }.into_any()
    } else {
        view! {}.into_any()
    }
}

#[component]
pub fn PersonalStatusMenu(user: Store<User>, set_open: WriteSignal<bool>) -> impl IntoView {
    let set_app: WriteSignal<AppState> = use_context().unwrap();
    let show_settings: RwSignal<Option<SettingsPage>> = use_context().unwrap();
    let user_presences: Store<UserPresences> = use_context().expect("no user presence store");
    
    let client = use_context::<Client>().expect("client not in context");
    let client1 = client.clone();
    let (show_value, set_show_value) = signal({
        let show = match user_presences.write().get_user_presences(&user.jid().read()).write().resource_presence(client.resource.read().clone().unwrap_or_default()).presence {
        PresenceType::Online(online) => match online.show {
            Some(s) => match s {
                Show::Away => 3,
                Show::Chat => 0,
                Show::DoNotDisturb => 2,
                Show::ExtendedAway => 4,
            },
            None => 1,
        },
        PresenceType::Offline(_offline) => 5,
    };
    debug!("initial show = {show}");
    show
    });

    let show_select: NodeRef<html::Select> = NodeRef::new();

    let disconnect = Action::new_local(move |()| {
        let client = client.clone();
        async move {
            client.disconnect(Offline::default()).await;
        }
    });
    let set_status = Action::new_local(move |show_value: &i32| {
        let show_value = show_value.to_owned();    
        let client = client1.clone();
        async move {
            if let Err(e) = match show_value {
                0 => {
                    if let Ok(r) = client.connect().await {
                        client.resource.set(Some(r))
                    };
                    client.set_status(Online { show: Some(Show::Chat), ..Default::default() }).await
                },
                1 => {
                    if let Ok(r) = client.connect().await {
                        client.resource.set(Some(r))
                    };
                    client.set_status(Online { show: None, ..Default::default() }).await
                },
                2 => {
                    if let Ok(r) = client.connect().await {
                        client.resource.set(Some(r))
                    };
                    client.set_status(Online { show: Some(Show::DoNotDisturb), ..Default::default() }).await
                },
                3 => {
                    if let Ok(r) = client.connect().await {
                        client.resource.set(Some(r))
                    };
                    client.set_status(Online { show: Some(Show::Away), ..Default::default() }).await
                },
                4 => {
                    if let Ok(r) = client.connect().await {
                        client.resource.set(Some(r))
                    };
                    client.set_status(Online { show: Some(Show::ExtendedAway), ..Default::default() }).await
                },
                5 => {
                    if let Ok(_) = client.disconnect(Offline::default()).await {
                        client.resource.set(None)
                    }
                    set_show_value.set(5);
                    return
                }
                _ => {
                    error!("invalid availability select");
                    return
                }
            } {
                error!("show set error: {e}");
                return
            }
            set_show_value.set(show_value);
        }
    });

    view! {
        <div class="personal-status-menu menu">
            <div class="user">
                <AvatarWithPresence user=user />
                <div class="user-info">
                    <div class="nick">{move || get_name(user, false)}</div>
                    <div class="jid">{move || user.jid().with(|jid| jid.to_string())}</div>
                </div>
            </div>
            <div class="status-edit">
                <select
                    node_ref=show_select
                    on:change:target=move |ev| {
                        let show_value = ev.target().value().parse().unwrap();
                        set_status.dispatch(show_value);
                    }
                    prop:show_value=move || show_value.get().to_string()
                >
                    <option value="0" selected=move || show_value.get_untracked() == 0>Available to Chat</option>
                    <option value="1" selected=move || show_value.get_untracked() == 1>Online</option>
                    <option value="2" selected=move || show_value.get_untracked() == 2>Do not disturb</option>
                    <option value="3" selected=move || show_value.get_untracked() == 3>Away</option>
                    <option value="4" selected=move || show_value.get_untracked() == 4>Extended Away</option>
                    <option value="5" selected=move || show_value.get_untracked() == 5>Offline</option>
                </select>
            </div>
            <hr />
            <div class="menu-item" on:click=move |_| {
                show_settings.set(Some(SettingsPage::Profile));
                set_open.set(false);
            }>
                Profile
            </div>
            <div class="menu-item" on:click=move |_| {
                show_settings.set(Some(SettingsPage::Account));
                set_open.set(false);
            }>
                Settings
            </div>
            <hr />
            <div class="menu-item" on:click=move |_| {
                // TODO: check if client is actually dropped/shutdown eventually
                disconnect.dispatch(());
                set_app.set(AppState::LoggedOut)
            }>
                Log out
            </div>
        </div>
    }
}