diff --git a/ui/src/layouts/log_in/copy_seed_words.rs b/ui/src/layouts/log_in/copy_seed_words.rs index c8ce8609a0a..227ad31af7f 100644 --- a/ui/src/layouts/log_in/copy_seed_words.rs +++ b/ui/src/layouts/log_in/copy_seed_words.rs @@ -7,13 +7,21 @@ use dioxus_desktop::{use_window, LogicalSize}; use kit::elements::{button::Button, label::Label, Appearance}; use tokio::time::sleep; -use crate::get_app_style; - use super::AuthPages; +use crate::get_app_style; +use common::state::configuration::Configuration; +use common::{ + sounds, + warp_runner::{MultiPassCmd, WarpCmd}, + WARP_CMD_CH, +}; +use futures::channel::oneshot; +use futures::StreamExt; +use warp::multipass; // styles for this layout are in layouts/style.scss #[component] -pub fn Layout(cx: Scope, page: UseState, seed_words: UseRef) -> Element { +pub fn Layout(cx: Scope, page: UseState, username: String, pin: String) -> Element { let state = use_ref(cx, State::load); let window = use_window(cx); @@ -24,20 +32,18 @@ pub fn Layout(cx: Scope, page: UseState, seed_words: UseRef) }); } - let words = use_future(cx, (), |_| { - to_owned![seed_words]; - async move { - let mnemonic = warp::crypto::keypair::generate_mnemonic_phrase( - warp::crypto::keypair::PhraseType::Standard, - ) - .into_phrase(); - - seed_words.set(mnemonic.clone()); + let words = use_future(cx, (), |_| async move { + let mnemonic = warp::crypto::keypair::generate_mnemonic_phrase( + warp::crypto::keypair::PhraseType::Standard, + ) + .into_phrase(); + ( + mnemonic.clone(), mnemonic .split_ascii_whitespace() .map(|x| x.to_string()) - .collect::>() - } + .collect::>(), + ) }); cx.render(rsx!( @@ -53,25 +59,76 @@ pub fn Layout(cx: Scope, page: UseState, seed_words: UseRef) aria_label: "copy-seed-words".into(), text: get_local_text("copy-seed-words") }, - if let Some(words) = words.value() { - rsx!{ SeedWords { page: page.clone(), words: words.clone() } } + if let Some((seed_words, words)) = words.value() { + rsx!{ SeedWords { page: page.clone(), username: username.clone(), pin: pin.clone(), seed_words: seed_words.clone(), words: words.clone() } } } } )) } #[component] -fn SeedWords(cx: Scope, page: UseState, words: Vec) -> Element { +fn SeedWords( + cx: Scope, + page: UseState, + username: String, + pin: String, + seed_words: String, + words: Vec, +) -> Element { let copied = use_ref(cx, || false); + let loading = use_state(cx, || false); + use_future(cx, copied, |current| async move { if *current.read() { sleep(Duration::from_secs(3)).await; *current.write() = false; } }); + + let ch = use_coroutine(cx, |mut rx: UnboundedReceiver<()>| { + to_owned![page, loading, username, pin, seed_words]; + async move { + let config = Configuration::load_or_default(); + let warp_cmd_tx = WARP_CMD_CH.tx.clone(); + while let Some(()) = rx.next().await { + loading.set(true); + let (tx, rx) = + oneshot::channel::>(); + + if let Err(e) = warp_cmd_tx.send(WarpCmd::MultiPass(MultiPassCmd::CreateIdentity { + username: username.clone(), + tesseract_passphrase: pin.clone(), + seed_words: seed_words.clone(), + rsp: tx, + })) { + log::error!("failed to send warp command: {}", e); + continue; + } + + let res = rx.await.expect("failed to get response from warp_runner"); + + match res { + Ok(ident) => { + if config.audiovideo.interface_sounds { + sounds::Play(sounds::Sounds::On); + } + + page.set(AuthPages::Success(ident)); + } + // todo: notify user + Err(e) => log::error!("create identity failed: {}", e), + } + } + } + }); render! { + loading.get().then(|| rsx!( + div { + class: "overlay-load-shadow", + }, + )), div { - class: "seed-words", + class: format_args!("seed-words {}", if *loading.get() {"progress"} else {""}), words.chunks_exact(2).enumerate().map(|(idx, vals)| rsx! { div { class: "row", @@ -126,6 +183,7 @@ fn SeedWords(cx: Scope, page: UseState, words: Vec) -> Elemen class: "controls", Button { text: get_local_text("uplink.go-back"), + disabled: *loading.get(), aria_label: "back-button".into(), icon: icons::outline::Shape::ChevronLeft, onpress: move |_| page.set(AuthPages::CreateOrRecover), @@ -133,9 +191,11 @@ fn SeedWords(cx: Scope, page: UseState, words: Vec) -> Elemen }, Button { aria_label: "i-saved-it-button".into(), + disabled: *loading.get(), + loading: *loading.get(), text: get_local_text("copy-seed-words.finished"), onpress: move |_| { - page.set(AuthPages::EnterUserName); + ch.send(()); } } } diff --git a/ui/src/layouts/log_in/create_or_recover.rs b/ui/src/layouts/log_in/create_or_recover.rs index 95019d94430..de4ac003793 100644 --- a/ui/src/layouts/log_in/create_or_recover.rs +++ b/ui/src/layouts/log_in/create_or_recover.rs @@ -39,7 +39,7 @@ pub fn Layout(cx: Scope, page: UseState) -> Element { aria_label: "create-button".into(), text: get_local_text("create-or-recover.create"), onpress: move |_| { - page.set(AuthPages::CopySeedWords); + page.set(AuthPages::EnterUserName); } }, Button { diff --git a/ui/src/layouts/log_in/enter_username.rs b/ui/src/layouts/log_in/enter_username.rs index b8be5cd61ff..c37531aa480 100644 --- a/ui/src/layouts/log_in/enter_username.rs +++ b/ui/src/layouts/log_in/enter_username.rs @@ -1,44 +1,23 @@ use common::icons::outline::Shape as Icon; use common::language::get_local_text; -use common::state::configuration::Configuration; -use common::{ - sounds, - warp_runner::{MultiPassCmd, WarpCmd}, - WARP_CMD_CH, -}; use dioxus::prelude::*; use dioxus_desktop::{use_window, LogicalSize}; -use futures::channel::oneshot; -use futures::StreamExt; use kit::elements::label::Label; use kit::elements::{ button::Button, input::{Input, Options, Validation}, }; use tracing::log; -use warp::multipass; use crate::AuthPages; pub const MIN_USERNAME_LEN: i32 = 4; pub const MAX_USERNAME_LEN: i32 = 32; -struct CreateAccountCmd { - username: String, - passphrase: String, - seed_words: String, -} - #[component] -pub fn Layout( - cx: Scope, - page: UseState, - pin: UseRef, - seed_words: UseRef, -) -> Element { +pub fn Layout(cx: Scope, page: UseState, user_name: UseRef) -> Element { log::trace!("rendering enter username layout"); let window = use_window(cx); - let loading = use_state(cx, || false); if !matches!(&*page.current(), AuthPages::Success(_)) { window.set_inner_size(LogicalSize { @@ -47,7 +26,6 @@ pub fn Layout( }); } - let username = use_state(cx, String::new); //let error = use_state(cx, String::new); let button_disabled = use_state(cx, || true); @@ -67,57 +45,9 @@ pub fn Layout( special_chars: None, }; - let ch = use_coroutine(cx, |mut rx: UnboundedReceiver| { - to_owned![page, loading]; - async move { - let config = Configuration::load_or_default(); - let warp_cmd_tx = WARP_CMD_CH.tx.clone(); - while let Some(CreateAccountCmd { - username, - passphrase, - seed_words, - }) = rx.next().await - { - loading.set(true); - let (tx, rx) = - oneshot::channel::>(); - - if let Err(e) = warp_cmd_tx.send(WarpCmd::MultiPass(MultiPassCmd::CreateIdentity { - username, - tesseract_passphrase: passphrase, - seed_words, - rsp: tx, - })) { - log::error!("failed to send warp command: {}", e); - continue; - } - - let res = rx.await.expect("failed to get response from warp_runner"); - - match res { - Ok(ident) => { - if config.audiovideo.interface_sounds { - sounds::Play(sounds::Sounds::On); - } - - page.set(AuthPages::Success(ident)); - } - // todo: notify user - Err(e) => log::error!("create identity failed: {}", e), - } - } - } - }); - cx.render(rsx!( - loading.get().then(|| rsx!( - div { - class: "overlay-load-shadow", - }, - )), div { id: "unlock-layout", - class: format_args!("{}", if *loading.get() {"progress"} else {""}), aria_label: "unlock-layout", Label { text: get_local_text("auth.enter-username") @@ -134,7 +64,6 @@ pub fn Layout( icon: Icon::Identification, aria_label: "username-input".into(), disable_onblur: true, - disabled: *loading.get(), placeholder: get_local_text("auth.enter-username"), options: Options { with_validation: Some(username_validation), @@ -147,15 +76,11 @@ pub fn Layout( if *button_disabled.get() != should_disable { button_disabled.set(should_disable); } - username.set(val); + user_name.set(val); }, onreturn: move |_| { if !*button_disabled.get() { - ch.send(CreateAccountCmd { - username: username.get().to_string(), - passphrase: pin.read().to_string(), - seed_words: seed_words.read().to_string() - }); + page.set(AuthPages::CopySeedWords); } } }, @@ -163,14 +88,9 @@ pub fn Layout( text: get_local_text("unlock.create-account"), aria_label: "create-account-button".into(), appearance: kit::elements::Appearance::Primary, - loading: *loading.get(), - disabled: *button_disabled.get() || *loading.get(), + disabled: *button_disabled.get(), onpress: move |_| { - ch.send(CreateAccountCmd { - username: username.get().to_string(), - passphrase: pin.read().to_string(), - seed_words: seed_words.read().to_string() - }); + page.set(AuthPages::CopySeedWords); } } } diff --git a/ui/src/layouts/log_in/mod.rs b/ui/src/layouts/log_in/mod.rs index 866e36efc66..94735ca4375 100644 --- a/ui/src/layouts/log_in/mod.rs +++ b/ui/src/layouts/log_in/mod.rs @@ -34,7 +34,7 @@ pub fn AuthGuard(cx: Scope, page: UseState) -> Element { log::trace!("rendering auth guard"); let pin = use_ref(cx, String::new); - let seed_words = use_ref(cx, String::new); + let user_name = use_ref(cx, String::new); let desktop = use_window(cx); let theme = ""; @@ -64,10 +64,10 @@ pub fn AuthGuard(cx: Scope, page: UseState) -> Element { match *page.current() { AuthPages::EntryPoint => rsx!(entry_point::Layout { page: page.clone(), pin: pin.clone() }), - AuthPages::EnterUserName => rsx!(enter_username::Layout { page: page.clone(), pin: pin.clone(), seed_words: seed_words.clone() }), + AuthPages::EnterUserName => rsx!(enter_username::Layout { page: page.clone(), user_name: user_name.clone() }), AuthPages::CreateOrRecover => rsx!(create_or_recover::Layout { page: page.clone() }), AuthPages::EnterSeedWords => rsx!(enter_seed_words::Layout { page: page.clone(), pin: pin.clone(), }), - AuthPages::CopySeedWords => rsx!(copy_seed_words::Layout { page: page.clone(), seed_words: seed_words.clone() }), + AuthPages::CopySeedWords => rsx!(copy_seed_words::Layout { page: page.clone(), username: user_name.read().clone(), pin: pin.read().clone() }), _ => unreachable!("this view should disappear when an account is unlocked or created"), } }