From 6ee4190a26f32bfa953302ee363ad3bb6c384ebb Mon Sep 17 00:00:00 2001 From: cel 🌸 Date: Sun, 1 Jun 2025 16:10:26 +0100 Subject: refactor: reorganise code --- src/views/macaw/settings.rs | 170 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 src/views/macaw/settings.rs (limited to 'src/views/macaw/settings.rs') diff --git a/src/views/macaw/settings.rs b/src/views/macaw/settings.rs new file mode 100644 index 0000000..11a3fc3 --- /dev/null +++ b/src/views/macaw/settings.rs @@ -0,0 +1,170 @@ +use leptos::prelude::*; +use profile_settings::ProfileSettings; + +use crate::{components::{icon::IconComponent, modal::Modal}, icon::Icon}; + +mod profile_settings { + use filamento::error::{AvatarPublishError, CommandError}; + use thiserror::Error; + use leptos::prelude::*; + use web_sys::{js_sys::Uint8Array, wasm_bindgen::{prelude::Closure, JsCast, UnwrapThrowExt}, Event, FileReader, HtmlInputElement, ProgressEvent}; + + use crate::{client::Client, files::Files}; + + #[derive(Debug, Clone, Error)] + pub enum ProfileSaveError { + #[error("avatar publish: {0}")] + Avatar(#[from] CommandError>), + } + + #[component] + pub fn ProfileSettings() -> impl IntoView { + let client: Client = use_context().expect("no client in context"); + + // TODO: compartmentalise into error component, form component... + let (error, set_error) = signal(None::); + let error_message = move || { + error.with(|error| { + if let Some(error) = error { + view! {
{error.to_string()}
}.into_any() + } else { + view! {}.into_any() + } + }) + }; + let (profile_save_pending, set_profile_save_pending) = signal(false); + + let profile_upload_data = RwSignal::new(None::>); + let from_input = move |ev: Event| { + let elem = ev.target().unwrap().unchecked_into::(); + + // let UploadSignal(file_signal) = expect_context(); + // file_signal.update(Vec::clear); // Clear list from previous change + let files = elem.files().unwrap_throw(); + + if let Some(file) = files.get(0) { + let reader = FileReader::new().unwrap_throw(); + // let name = file.name(); + + // This closure only needs to be called a single time as we will just + // remake it on each loop + // * web_sys drops it for us when using this specific constructor + let read_file = { + // FileReader is cloned prior to moving into the closure + let reader = reader.to_owned(); + Closure::once_into_js(move |_: ProgressEvent| { + // `.result` valid after the `read_*` completes on FileReader + // https://developer.mozilla.org/en-US/docs/Web/API/FileReader/result + let result = reader.result().unwrap_throw(); + let data= Uint8Array::new(&result).to_vec(); + // Do whatever you want with the Vec + profile_upload_data.set(Some(data)); + }) + }; + reader.set_onloadend(Some(read_file.as_ref().unchecked_ref())); + + // read_as_array_buffer takes a &Blob + // + // Per https://w3c.github.io/FileAPI/#file-section + // > A File object is a Blob object with a name attribute.. + // + // File is a subclass (inherits) from the Blob interface, so a File + // can be used anywhere a Blob is required. + reader.read_as_array_buffer(&file).unwrap_throw(); + + // You can also use `.read_as_text(&file)` instead if you just want a string. + // This example shows how to extract an array buffer as it is more flexible + // + // If you use `.read_as_text` change the closure from ... + // + // let result = reader.result().unwrap_throw(); + // let vec_of_u8_bytes = Uint8Array::new(&result).to_vec(); + // let content = String::from_utf8(vec_of_u8_bytes).unwrap_throw(); + // + // to ... + // + // let result = reader.result().unwrap_throw(); + // let content = result.as_string().unwrap_throw(); + } else { + profile_upload_data.set(None); + } + }; + + let save_profile = Action::new_local(move |_| { + let client = client.clone(); + async move {} + }); + + let new_nick= RwSignal::new("".to_string()); + + view! { +
+
+ {error_message} +
+ +
+ + +
+
+
+

Profile Preview

+
+ +
nick
+
+
+ } + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum SettingsPage { + Account, + Chat, + Profile, + Privacy, +} + +#[component] +pub fn Settings() -> impl IntoView { + let show_settings: RwSignal> = use_context().unwrap(); + + view! { + +
+
+

Settings

+
+ +
+
+
+
+
Account
+
Chat
+
Privacy
+
Profile
+
+
+ {move || if let Some(page) = show_settings.get() { + match page { + SettingsPage::Account => view! {
"account"
}.into_any(), + SettingsPage::Chat => view! {
"chat"
}.into_any(), + SettingsPage::Profile => view! { }.into_any(), + SettingsPage::Privacy => view! {
"privacy"
}.into_any(), + } + } else { + view! {}.into_any() + }} +
+
+
+
+ } +} + -- cgit