Separate login from choose backend step
This commit is contained in:
parent
e6c592955e
commit
c75f909dc9
@ -17,6 +17,8 @@ use liana::{
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum RemoteBackend {
|
||||
Undefined,
|
||||
None,
|
||||
// The installer will have to create a wallet from the created descriptor.
|
||||
WithoutWallet(BackendClient),
|
||||
// The installer will have to fetch the wallet and only install the missing configuration files.
|
||||
@ -24,12 +26,23 @@ pub enum RemoteBackend {
|
||||
}
|
||||
|
||||
impl RemoteBackend {
|
||||
pub fn user_email(&self) -> &str {
|
||||
pub fn user_email(&self) -> Option<&str> {
|
||||
match self {
|
||||
Self::WithWallet(b) => b.user_email(),
|
||||
Self::WithoutWallet(b) => b.user_email(),
|
||||
Self::WithWallet(b) => Some(b.user_email()),
|
||||
Self::WithoutWallet(b) => Some(b.user_email()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_none(&self) -> bool {
|
||||
matches!(self, RemoteBackend::None)
|
||||
}
|
||||
pub fn is_some(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
RemoteBackend::WithoutWallet { .. } | RemoteBackend::WithWallet { .. }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@ -48,14 +61,14 @@ pub struct Context {
|
||||
pub bitcoind_is_external: bool,
|
||||
pub internal_bitcoind_config: Option<InternalBitcoindConfig>,
|
||||
pub internal_bitcoind: Option<Bitcoind>,
|
||||
pub remote_backend: Option<RemoteBackend>,
|
||||
pub remote_backend: RemoteBackend,
|
||||
}
|
||||
|
||||
impl Context {
|
||||
pub fn new(
|
||||
network: bitcoin::Network,
|
||||
data_dir: PathBuf,
|
||||
remote_backend: Option<RemoteBackend>,
|
||||
remote_backend: RemoteBackend,
|
||||
) -> Self {
|
||||
Self {
|
||||
bitcoin_config: BitcoinConfig {
|
||||
|
||||
@ -49,8 +49,7 @@ pub enum SelectBackend {
|
||||
EditEmail,
|
||||
EmailEdited(String),
|
||||
OTPEdited(String),
|
||||
ContinueWithRemoteBackend,
|
||||
ContinueWithLocalWallet,
|
||||
ContinueWithLocalWallet(bool),
|
||||
// Commands messages
|
||||
OTPRequested(Result<(AuthClient, String), Error>),
|
||||
OTPResent(Result<(), Error>),
|
||||
|
||||
@ -41,7 +41,7 @@ pub use message::Message;
|
||||
use step::{
|
||||
BackupDescriptor, BackupMnemonic, ChooseBackend, DefineBitcoind, DefineDescriptor, Final,
|
||||
ImportDescriptor, ImportRemoteWallet, InternalBitcoindStep, RecoverMnemonic,
|
||||
RegisterDescriptor, SelectBitcoindTypeStep, ShareXpubs, Step,
|
||||
RegisterDescriptor, RemoteBackendLogin, SelectBitcoindTypeStep, ShareXpubs, Step,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@ -73,14 +73,17 @@ impl Installer {
|
||||
return Command::perform(async move { network }, Message::BackToLauncher);
|
||||
}
|
||||
// skip the previous step according to the current context.
|
||||
while self.current > 0
|
||||
&& self
|
||||
.steps
|
||||
.get(self.current)
|
||||
.expect("There is always a step")
|
||||
.skip(&self.context)
|
||||
while self
|
||||
.steps
|
||||
.get(self.current)
|
||||
.expect("There is always a step")
|
||||
.skip(&self.context)
|
||||
{
|
||||
self.current -= 1;
|
||||
if self.current > 0 {
|
||||
self.current -= 1;
|
||||
} else {
|
||||
return Command::perform(async move { network }, Message::BackToLauncher);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(step) = self.steps.get(self.current) {
|
||||
@ -99,7 +102,9 @@ impl Installer {
|
||||
let context = Context::new(
|
||||
network,
|
||||
destination_path.clone(),
|
||||
remote_backend.map(RemoteBackend::WithoutWallet),
|
||||
remote_backend
|
||||
.map(RemoteBackend::WithoutWallet)
|
||||
.unwrap_or(RemoteBackend::Undefined),
|
||||
);
|
||||
let mut installer = Installer {
|
||||
network,
|
||||
@ -113,6 +118,7 @@ impl Installer {
|
||||
BackupDescriptor::default().into(),
|
||||
RegisterDescriptor::new_create_wallet().into(),
|
||||
ChooseBackend::new(network).into(),
|
||||
RemoteBackendLogin::new(network).into(),
|
||||
SelectBitcoindTypeStep::new().into(),
|
||||
InternalBitcoindStep::new(&context.data_dir).into(),
|
||||
DefineBitcoind::new().into(),
|
||||
@ -121,6 +127,7 @@ impl Installer {
|
||||
UserFlow::ShareXpubs => vec![ShareXpubs::new(network, signer.clone()).into()],
|
||||
UserFlow::AddWallet => vec![
|
||||
ChooseBackend::new(network).into(),
|
||||
RemoteBackendLogin::new(network).into(),
|
||||
ImportRemoteWallet::new(network).into(),
|
||||
ImportDescriptor::new(network).into(),
|
||||
RecoverMnemonic::default().into(),
|
||||
@ -134,6 +141,9 @@ impl Installer {
|
||||
context,
|
||||
signer,
|
||||
};
|
||||
// skip the step according to the current context.
|
||||
installer.skip_steps();
|
||||
|
||||
let current_step = installer
|
||||
.steps
|
||||
.get_mut(installer.current)
|
||||
@ -167,6 +177,19 @@ impl Installer {
|
||||
self.context.internal_bitcoind = None;
|
||||
}
|
||||
|
||||
fn skip_steps(&mut self) {
|
||||
while self
|
||||
.steps
|
||||
.get(self.current)
|
||||
.expect("There is always a step")
|
||||
.skip(&self.context)
|
||||
{
|
||||
if self.current < self.steps.len() - 1 {
|
||||
self.current += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn next(&mut self) -> Command<Message> {
|
||||
let current_step = self
|
||||
.steps
|
||||
@ -181,16 +204,8 @@ impl Installer {
|
||||
return Command::none();
|
||||
}
|
||||
// skip the step according to the current context.
|
||||
while self
|
||||
.steps
|
||||
.get(self.current)
|
||||
.expect("There is always a step")
|
||||
.skip(&self.context)
|
||||
{
|
||||
if self.current < self.steps.len() - 1 {
|
||||
self.current += 1;
|
||||
}
|
||||
}
|
||||
self.skip_steps();
|
||||
|
||||
// calculate new current_step.
|
||||
let current_step = self
|
||||
.steps
|
||||
@ -221,7 +236,7 @@ impl Installer {
|
||||
.expect("There is always a step")
|
||||
.update(&mut self.hws, message);
|
||||
match &self.context.remote_backend {
|
||||
Some(RemoteBackend::WithoutWallet(backend)) => Command::perform(
|
||||
RemoteBackend::WithoutWallet(backend) => Command::perform(
|
||||
create_remote_wallet(
|
||||
self.context.clone(),
|
||||
self.signer.clone(),
|
||||
@ -229,14 +244,15 @@ impl Installer {
|
||||
),
|
||||
Message::Installed,
|
||||
),
|
||||
Some(RemoteBackend::WithWallet(backend)) => Command::perform(
|
||||
RemoteBackend::WithWallet(backend) => Command::perform(
|
||||
import_remote_wallet(self.context.clone(), backend.clone()),
|
||||
Message::Installed,
|
||||
),
|
||||
None => Command::perform(
|
||||
RemoteBackend::None => Command::perform(
|
||||
install_local_wallet(self.context.clone(), self.signer.clone()),
|
||||
Message::Installed,
|
||||
),
|
||||
RemoteBackend::Undefined => unreachable!("Must be defined at this point"),
|
||||
}
|
||||
}
|
||||
Message::Installed(Err(e)) => {
|
||||
@ -295,7 +311,7 @@ impl Installer {
|
||||
.view(
|
||||
&self.hws,
|
||||
self.progress(),
|
||||
self.context.remote_backend.as_ref().map(|b| b.user_email()),
|
||||
self.context.remote_backend.user_email(),
|
||||
);
|
||||
|
||||
if self.network != Network::Bitcoin {
|
||||
|
||||
@ -21,6 +21,64 @@ use crate::{
|
||||
},
|
||||
};
|
||||
|
||||
pub struct ChooseBackend {
|
||||
network: Network,
|
||||
remote_backend_is_selected: bool,
|
||||
}
|
||||
|
||||
impl ChooseBackend {
|
||||
pub fn new(network: Network) -> Self {
|
||||
Self {
|
||||
network,
|
||||
remote_backend_is_selected: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ChooseBackend> for Box<dyn Step> {
|
||||
fn from(s: ChooseBackend) -> Box<dyn Step> {
|
||||
Box::new(s)
|
||||
}
|
||||
}
|
||||
impl Step for ChooseBackend {
|
||||
fn skip(&self, _ctx: &Context) -> bool {
|
||||
self.network != Network::Bitcoin && self.network != Network::Signet
|
||||
}
|
||||
fn update(&mut self, _hws: &mut HardwareWallets, message: Message) -> Command<Message> {
|
||||
if let Message::SelectBackend(message::SelectBackend::ContinueWithLocalWallet(
|
||||
local_wallet,
|
||||
)) = message
|
||||
{
|
||||
self.remote_backend_is_selected = !local_wallet;
|
||||
Command::perform(async move {}, |_| Message::Next)
|
||||
} else {
|
||||
Command::none()
|
||||
}
|
||||
}
|
||||
|
||||
fn apply(&mut self, ctx: &mut Context) -> bool {
|
||||
if !self.remote_backend_is_selected {
|
||||
ctx.remote_backend = RemoteBackend::None;
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
/// If user clicks on previous to get back to the select backend, we revert the applied remote
|
||||
/// backend on the context.
|
||||
fn revert(&self, ctx: &mut Context) {
|
||||
ctx.remote_backend = RemoteBackend::Undefined;
|
||||
}
|
||||
|
||||
fn view<'a>(
|
||||
&'a self,
|
||||
_hws: &'a HardwareWallets,
|
||||
progress: (usize, usize),
|
||||
_email: Option<&'a str>,
|
||||
) -> Element<Message> {
|
||||
view::choose_backend(progress)
|
||||
}
|
||||
}
|
||||
|
||||
pub enum ConnectionStep {
|
||||
EnterEmail {
|
||||
email: form::Value<String>,
|
||||
@ -34,11 +92,10 @@ pub enum ConnectionStep {
|
||||
Connected {
|
||||
email: String,
|
||||
remote_backend: context::RemoteBackend,
|
||||
remote_backend_is_selected: bool,
|
||||
},
|
||||
}
|
||||
|
||||
pub struct ChooseBackend {
|
||||
pub struct RemoteBackendLogin {
|
||||
network: Network,
|
||||
processing: bool,
|
||||
step: ConnectionStep,
|
||||
@ -46,7 +103,7 @@ pub struct ChooseBackend {
|
||||
auth_error: Option<&'static str>,
|
||||
}
|
||||
|
||||
impl ChooseBackend {
|
||||
impl RemoteBackendLogin {
|
||||
pub fn new(network: Network) -> Self {
|
||||
Self {
|
||||
network,
|
||||
@ -60,30 +117,18 @@ impl ChooseBackend {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ChooseBackend> for Box<dyn Step> {
|
||||
fn from(s: ChooseBackend) -> Box<dyn Step> {
|
||||
impl From<RemoteBackendLogin> for Box<dyn Step> {
|
||||
fn from(s: RemoteBackendLogin) -> Box<dyn Step> {
|
||||
Box::new(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl Step for ChooseBackend {
|
||||
fn skip(&self, _ctx: &Context) -> bool {
|
||||
self.network != Network::Bitcoin && self.network != Network::Signet
|
||||
impl Step for RemoteBackendLogin {
|
||||
fn skip(&self, ctx: &Context) -> bool {
|
||||
matches!(ctx.remote_backend, RemoteBackend::None)
|
||||
|| (self.network != Network::Bitcoin && self.network != Network::Signet)
|
||||
}
|
||||
fn update(&mut self, _hws: &mut HardwareWallets, message: Message) -> Command<Message> {
|
||||
if matches!(
|
||||
message,
|
||||
Message::SelectBackend(message::SelectBackend::ContinueWithLocalWallet)
|
||||
) {
|
||||
if let ConnectionStep::Connected {
|
||||
remote_backend_is_selected,
|
||||
..
|
||||
} = &mut self.step
|
||||
{
|
||||
*remote_backend_is_selected = false;
|
||||
}
|
||||
return Command::perform(async move {}, |_| Message::Next);
|
||||
}
|
||||
match &mut self.step {
|
||||
ConnectionStep::EnterEmail { email } => match message {
|
||||
Message::SelectBackend(message::SelectBackend::EmailEdited(value)) => {
|
||||
@ -206,7 +251,6 @@ impl Step for ChooseBackend {
|
||||
self.step = ConnectionStep::Connected {
|
||||
email: email.clone(),
|
||||
remote_backend,
|
||||
remote_backend_is_selected: false,
|
||||
};
|
||||
}
|
||||
Err(e) => {
|
||||
@ -224,38 +268,23 @@ impl Step for ChooseBackend {
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
ConnectionStep::Connected {
|
||||
remote_backend_is_selected,
|
||||
..
|
||||
} => match message {
|
||||
Message::SelectBackend(message::SelectBackend::EditEmail) => {
|
||||
ConnectionStep::Connected { .. } => {
|
||||
if let Message::SelectBackend(message::SelectBackend::EditEmail) = message {
|
||||
self.step = ConnectionStep::EnterEmail {
|
||||
email: form::Value::default(),
|
||||
}
|
||||
}
|
||||
Message::SelectBackend(message::SelectBackend::ContinueWithRemoteBackend) => {
|
||||
*remote_backend_is_selected = true;
|
||||
return Command::perform(async move {}, |_| Message::Next);
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
Command::none()
|
||||
}
|
||||
|
||||
fn apply(&mut self, ctx: &mut Context) -> bool {
|
||||
if let ConnectionStep::Connected {
|
||||
remote_backend,
|
||||
remote_backend_is_selected,
|
||||
..
|
||||
} = &self.step
|
||||
{
|
||||
if *remote_backend_is_selected {
|
||||
ctx.remote_backend = Some(remote_backend.clone());
|
||||
}
|
||||
if let ConnectionStep::Connected { remote_backend, .. } = &self.step {
|
||||
ctx.remote_backend = remote_backend.clone();
|
||||
} else {
|
||||
ctx.remote_backend = None;
|
||||
ctx.remote_backend = RemoteBackend::None;
|
||||
}
|
||||
|
||||
true
|
||||
@ -264,7 +293,7 @@ impl Step for ChooseBackend {
|
||||
/// If user clicks on previous to get back to the select backend, we revert the applied remote
|
||||
/// backend on the context.
|
||||
fn revert(&self, ctx: &mut Context) {
|
||||
ctx.remote_backend = None;
|
||||
ctx.remote_backend = RemoteBackend::Undefined;
|
||||
}
|
||||
|
||||
fn view<'a>(
|
||||
@ -273,7 +302,7 @@ impl Step for ChooseBackend {
|
||||
progress: (usize, usize),
|
||||
_email: Option<&'a str>,
|
||||
) -> Element<Message> {
|
||||
view::choose_backend(
|
||||
view::login(
|
||||
progress,
|
||||
match &self.step {
|
||||
ConnectionStep::EnterEmail { email } => view::connection_step_enter_email(
|
||||
@ -318,7 +347,7 @@ pub struct ImportRemoteWallet {
|
||||
imported_descriptor: form::Value<String>,
|
||||
descriptor: Option<LianaDescriptor>,
|
||||
error: Option<String>,
|
||||
backend: Option<context::RemoteBackend>,
|
||||
backend: context::RemoteBackend,
|
||||
wallets: Vec<api::Wallet>,
|
||||
}
|
||||
|
||||
@ -331,7 +360,7 @@ impl ImportRemoteWallet {
|
||||
imported_descriptor: form::Value::default(),
|
||||
descriptor: None,
|
||||
error: None,
|
||||
backend: None,
|
||||
backend: context::RemoteBackend::Undefined,
|
||||
wallets: Vec::new(),
|
||||
}
|
||||
}
|
||||
@ -339,16 +368,16 @@ impl ImportRemoteWallet {
|
||||
|
||||
impl Step for ImportRemoteWallet {
|
||||
fn skip(&self, ctx: &Context) -> bool {
|
||||
ctx.remote_backend.is_none()
|
||||
matches!(
|
||||
ctx.remote_backend,
|
||||
RemoteBackend::Undefined | RemoteBackend::None
|
||||
)
|
||||
}
|
||||
fn load_context(&mut self, ctx: &Context) {
|
||||
self.backend.clone_from(&ctx.remote_backend);
|
||||
self.backend = ctx.remote_backend.clone();
|
||||
}
|
||||
fn load(&self) -> Command<Message> {
|
||||
let backend = self
|
||||
.backend
|
||||
.clone()
|
||||
.expect("Must be one otherwise the step is skipped");
|
||||
let backend = self.backend.clone();
|
||||
Command::perform(
|
||||
async move {
|
||||
let wallets = match backend {
|
||||
@ -358,6 +387,7 @@ impl Step for ImportRemoteWallet {
|
||||
context::RemoteBackend::WithWallet(backend) => {
|
||||
backend.inner_client().list_wallets().await?
|
||||
}
|
||||
_ => unreachable!("Step must be skipped otherwise"),
|
||||
};
|
||||
|
||||
Ok(wallets)
|
||||
@ -394,12 +424,9 @@ impl Step for ImportRemoteWallet {
|
||||
self.imported_descriptor.valid = desc.all_xpubs_net_is(Network::Testnet);
|
||||
}
|
||||
if self.imported_descriptor.valid {
|
||||
let backend = self.backend.take();
|
||||
if let Some(context::RemoteBackend::WithWallet(backend)) = backend {
|
||||
if let context::RemoteBackend::WithWallet(backend) = self.backend.clone() {
|
||||
self.backend =
|
||||
Some(context::RemoteBackend::WithoutWallet(backend.into_inner()));
|
||||
} else {
|
||||
self.backend = backend;
|
||||
context::RemoteBackend::WithoutWallet(backend.into_inner());
|
||||
}
|
||||
self.descriptor = Some(desc);
|
||||
return Command::perform(async {}, |_| Message::Next);
|
||||
@ -420,14 +447,11 @@ impl Step for ImportRemoteWallet {
|
||||
self.invitation_token.value = token;
|
||||
}
|
||||
Message::ImportRemoteWallet(message::ImportRemoteWallet::FetchInvitation) => {
|
||||
let backend = self
|
||||
.backend
|
||||
.clone()
|
||||
.map(|b| match b {
|
||||
context::RemoteBackend::WithoutWallet(b) => b,
|
||||
context::RemoteBackend::WithWallet(b) => b.into_inner(),
|
||||
})
|
||||
.expect("Must be a remote backend at this point");
|
||||
let backend = match self.backend.clone() {
|
||||
context::RemoteBackend::WithoutWallet(b) => b,
|
||||
context::RemoteBackend::WithWallet(b) => b.into_inner(),
|
||||
_ => unreachable!("Must be a remote backend at this point"),
|
||||
};
|
||||
let token = self.invitation_token.value.clone();
|
||||
self.error = None;
|
||||
return Command::perform(
|
||||
@ -449,14 +473,11 @@ impl Step for ImportRemoteWallet {
|
||||
}
|
||||
}
|
||||
Message::ImportRemoteWallet(message::ImportRemoteWallet::AcceptInvitation) => {
|
||||
let backend = self
|
||||
.backend
|
||||
.clone()
|
||||
.map(|b| match b {
|
||||
context::RemoteBackend::WithoutWallet(b) => b,
|
||||
context::RemoteBackend::WithWallet(b) => b.into_inner(),
|
||||
})
|
||||
.expect("Must be a remote backend at this point");
|
||||
let backend = match self.backend.clone() {
|
||||
context::RemoteBackend::WithoutWallet(b) => b,
|
||||
context::RemoteBackend::WithWallet(b) => b.into_inner(),
|
||||
_ => unreachable!("Must be a remote backend defined"),
|
||||
};
|
||||
let invitation = self.invitation.clone().expect("Invitation was fetched");
|
||||
self.error = None;
|
||||
return Command::perform(
|
||||
@ -492,24 +513,24 @@ impl Step for ImportRemoteWallet {
|
||||
}
|
||||
Message::Select(i) => {
|
||||
if let Some(wallet) = self.wallets.get(i).cloned() {
|
||||
if let Some(backend) = self.backend.take() {
|
||||
self.backend = Some(match backend {
|
||||
context::RemoteBackend::WithoutWallet(backend) => {
|
||||
context::RemoteBackend::WithWallet(
|
||||
backend.connect_wallet(wallet.clone()).0,
|
||||
)
|
||||
}
|
||||
context::RemoteBackend::WithWallet(backend) => {
|
||||
context::RemoteBackend::WithWallet(
|
||||
backend.into_inner().connect_wallet(wallet.clone()).0,
|
||||
)
|
||||
}
|
||||
});
|
||||
// ensure that no descriptor is imported.
|
||||
self.imported_descriptor = form::Value::default();
|
||||
self.descriptor = Some(wallet.descriptor);
|
||||
return Command::perform(async {}, |_| Message::Next);
|
||||
}
|
||||
self.backend = match self.backend.clone() {
|
||||
context::RemoteBackend::WithoutWallet(backend) => {
|
||||
context::RemoteBackend::WithWallet(
|
||||
backend.connect_wallet(wallet.clone()).0,
|
||||
)
|
||||
}
|
||||
context::RemoteBackend::WithWallet(backend) => {
|
||||
context::RemoteBackend::WithWallet(
|
||||
backend.into_inner().connect_wallet(wallet.clone()).0,
|
||||
)
|
||||
}
|
||||
context::RemoteBackend::None => context::RemoteBackend::None,
|
||||
context::RemoteBackend::Undefined => context::RemoteBackend::Undefined,
|
||||
};
|
||||
// ensure that no descriptor is imported.
|
||||
self.imported_descriptor = form::Value::default();
|
||||
self.descriptor = Some(wallet.descriptor);
|
||||
return Command::perform(async {}, |_| Message::Next);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
||||
@ -1447,7 +1447,11 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_define_descriptor_use_hotkey() {
|
||||
let mut ctx = Context::new(Network::Signet, PathBuf::from_str("/").unwrap(), None);
|
||||
let mut ctx = Context::new(
|
||||
Network::Signet,
|
||||
PathBuf::from_str("/").unwrap(),
|
||||
crate::installer::context::RemoteBackend::None,
|
||||
);
|
||||
let sandbox: Sandbox<DefineDescriptor> = Sandbox::new(DefineDescriptor::new(
|
||||
Network::Bitcoin,
|
||||
Arc::new(Mutex::new(Signer::generate(Network::Bitcoin).unwrap())),
|
||||
@ -1529,7 +1533,11 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_define_descriptor_stores_if_hw_is_used() {
|
||||
let mut ctx = Context::new(Network::Testnet, PathBuf::from_str("/").unwrap(), None);
|
||||
let mut ctx = Context::new(
|
||||
Network::Testnet,
|
||||
PathBuf::from_str("/").unwrap(),
|
||||
crate::installer::context::RemoteBackend::None,
|
||||
);
|
||||
let sandbox: Sandbox<DefineDescriptor> = Sandbox::new(DefineDescriptor::new(
|
||||
Network::Testnet,
|
||||
Arc::new(Mutex::new(Signer::generate(Network::Testnet).unwrap())),
|
||||
|
||||
@ -10,7 +10,7 @@ pub use bitcoind::{
|
||||
|
||||
pub use descriptor::{BackupDescriptor, DefineDescriptor, ImportDescriptor, RegisterDescriptor};
|
||||
|
||||
pub use backend::{ChooseBackend, ImportRemoteWallet};
|
||||
pub use backend::{ChooseBackend, ImportRemoteWallet, RemoteBackendLogin};
|
||||
pub use mnemonic::{BackupMnemonic, RecoverMnemonic};
|
||||
pub use share_xpubs::ShareXpubs;
|
||||
|
||||
|
||||
@ -299,7 +299,7 @@ pub fn import_wallet_or_descriptor<'a>(
|
||||
) -> Element<'a, Message> {
|
||||
let mut col_wallets = Column::new()
|
||||
.spacing(20)
|
||||
.push(h4_bold("Choose the wallet to import"));
|
||||
.push(h4_bold("Load a previously used wallet"));
|
||||
let no_wallets = wallets.is_empty();
|
||||
for (i, wallet) in wallets.into_iter().enumerate() {
|
||||
col_wallets = col_wallets.push(
|
||||
@ -319,7 +319,7 @@ pub fn import_wallet_or_descriptor<'a>(
|
||||
Button::new(
|
||||
Column::new()
|
||||
.spacing(5)
|
||||
.push(h4_bold("Join a shared wallet").style(color::WHITE))
|
||||
.push(h4_bold("Load a shared wallet").style(color::WHITE))
|
||||
.push(
|
||||
text("If you received an invitation to join a shared wallet")
|
||||
.style(color::GREY_3),
|
||||
@ -333,9 +333,9 @@ pub fn import_wallet_or_descriptor<'a>(
|
||||
Button::new(
|
||||
Column::new()
|
||||
.spacing(5)
|
||||
.push(h4_bold("Join a shared wallet").style(color::WHITE))
|
||||
.push(h4_bold("Load a shared wallet").style(color::WHITE))
|
||||
.push(
|
||||
text("If you received an invitation to join a shared wallet")
|
||||
text("Type the invitation token you received by email")
|
||||
.style(color::GREY_3),
|
||||
),
|
||||
)
|
||||
@ -413,11 +413,8 @@ pub fn import_wallet_or_descriptor<'a>(
|
||||
Button::new(
|
||||
Column::new()
|
||||
.spacing(5)
|
||||
.push(h4_bold("Import a wallet from descriptor").style(color::WHITE))
|
||||
.push(
|
||||
text("The remote backend will rescan the blockchain to find your coins")
|
||||
.style(color::GREY_3),
|
||||
),
|
||||
.push(h4_bold("Load a wallet from descriptor").style(color::WHITE))
|
||||
.push(text("Creates a new wallet from the descriptor").style(color::GREY_3)),
|
||||
)
|
||||
.padding(15)
|
||||
.width(Length::Fill)
|
||||
@ -427,11 +424,8 @@ pub fn import_wallet_or_descriptor<'a>(
|
||||
Button::new(
|
||||
Column::new()
|
||||
.spacing(5)
|
||||
.push(h4_bold("Import a wallet from descriptor").style(color::WHITE))
|
||||
.push(
|
||||
text("The remote backend will rescan the blockchain to find your coins")
|
||||
.style(color::GREY_3),
|
||||
),
|
||||
.push(h4_bold("Load a wallet from descriptor").style(color::WHITE))
|
||||
.push(text("Creates a new wallet from the descriptor").style(color::GREY_3)),
|
||||
)
|
||||
.padding(15)
|
||||
.width(Length::Fill)
|
||||
@ -2264,10 +2258,7 @@ pub fn recover_mnemonic<'a>(
|
||||
)
|
||||
}
|
||||
|
||||
pub fn choose_backend(
|
||||
progress: (usize, usize),
|
||||
connection_step: Element<Message>,
|
||||
) -> Element<Message> {
|
||||
pub fn choose_backend(progress: (usize, usize)) -> Element<'static, Message> {
|
||||
layout(
|
||||
progress,
|
||||
None,
|
||||
@ -2279,27 +2270,64 @@ pub fn choose_backend(
|
||||
.push(
|
||||
Column::new()
|
||||
.spacing(20)
|
||||
.align_items(Alignment::Center)
|
||||
.width(Length::FillPortion(1))
|
||||
.push(image::liana_brand_grey().height(Length::Fixed(100.0)))
|
||||
.push(text::p2_medium(LIANA_DESC).style(color::GREY_3))
|
||||
.push(button::primary(None, "Install local wallet").on_press(
|
||||
Message::SelectBackend(
|
||||
message::SelectBackend::ContinueWithLocalWallet,
|
||||
),
|
||||
)),
|
||||
.push(text::p2_medium(LOCAL_WALLET_DESC).style(color::GREY_3)),
|
||||
)
|
||||
.push(
|
||||
Column::new()
|
||||
.spacing(20)
|
||||
.align_items(Alignment::Center)
|
||||
.width(Length::FillPortion(1))
|
||||
.push(image::wizardsardine().height(Length::Fixed(100.0)))
|
||||
.push(text::p2_medium(LIANALITE_DESC).style(color::GREY_3))
|
||||
.push(connection_step),
|
||||
.push(text::p2_medium(REMOTE_BACKEND_DESC).style(color::GREY_3)),
|
||||
),
|
||||
)
|
||||
.spacing(50),
|
||||
.push(
|
||||
Row::new()
|
||||
.spacing(20)
|
||||
.push(
|
||||
Container::new(
|
||||
button::primary(None, "Select")
|
||||
.on_press(Message::SelectBackend(
|
||||
message::SelectBackend::ContinueWithLocalWallet(true),
|
||||
))
|
||||
.width(Length::Fixed(200.0)),
|
||||
)
|
||||
.width(Length::FillPortion(1)),
|
||||
)
|
||||
.push(
|
||||
Container::new(
|
||||
button::primary(None, "Select")
|
||||
.on_press(Message::SelectBackend(
|
||||
message::SelectBackend::ContinueWithLocalWallet(false),
|
||||
))
|
||||
.width(Length::Fixed(200.0)),
|
||||
)
|
||||
.width(Length::FillPortion(1)),
|
||||
),
|
||||
)
|
||||
.spacing(20),
|
||||
true,
|
||||
Some(Message::Previous),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn login(progress: (usize, usize), connection_step: Element<Message>) -> Element<Message> {
|
||||
layout(
|
||||
progress,
|
||||
None,
|
||||
"Login",
|
||||
Container::new(
|
||||
Column::new()
|
||||
.spacing(50)
|
||||
.max_width(700)
|
||||
.align_items(Alignment::Center)
|
||||
.width(Length::FillPortion(1))
|
||||
.push(image::wizardsardine().height(Length::Fixed(100.0)))
|
||||
.push(connection_step),
|
||||
)
|
||||
.width(Length::Fill)
|
||||
.center_x(),
|
||||
true,
|
||||
Some(Message::Previous),
|
||||
)
|
||||
@ -2315,6 +2343,9 @@ pub fn connection_step_enter_email<'a>(
|
||||
.spacing(20)
|
||||
.push_maybe(connection_error.map(|e| text(e.to_string()).style(color::ORANGE)))
|
||||
.push_maybe(auth_error.map(|e| text(e.to_string()).style(color::ORANGE)))
|
||||
.push(text(
|
||||
"Enter the email you want to associate with the wallet:",
|
||||
))
|
||||
.push(
|
||||
form::Form::new_trimmed("email", email, |msg| {
|
||||
Message::SelectBackend(message::SelectBackend::EmailEdited(msg))
|
||||
@ -2324,11 +2355,13 @@ pub fn connection_step_enter_email<'a>(
|
||||
.warning("Email is not valid"),
|
||||
)
|
||||
.push(
|
||||
button::primary(None, "Next").on_press_maybe(if processing || !email.valid {
|
||||
None
|
||||
} else {
|
||||
Some(Message::SelectBackend(message::SelectBackend::RequestOTP))
|
||||
}),
|
||||
button::primary(None, "Next")
|
||||
.on_press_maybe(if processing || !email.valid {
|
||||
None
|
||||
} else {
|
||||
Some(Message::SelectBackend(message::SelectBackend::RequestOTP))
|
||||
})
|
||||
.width(Length::Fixed(200.0)),
|
||||
)
|
||||
.into()
|
||||
}
|
||||
@ -2394,18 +2427,16 @@ pub fn connection_step_connected<'a>(
|
||||
button::primary(None, "Continue").on_press_maybe(if processing {
|
||||
None
|
||||
} else {
|
||||
Some(Message::SelectBackend(
|
||||
message::SelectBackend::ContinueWithRemoteBackend,
|
||||
))
|
||||
Some(Message::Next)
|
||||
}),
|
||||
),
|
||||
))
|
||||
.into()
|
||||
}
|
||||
|
||||
pub const LIANALITE_DESC: &str = "Use the connection to the Bitcoin network provided by Wizardsardine. This removes the need for running a Bitcoin full node on your machine. It also provides synchronisation of your wallet data (labels, transactions, etc..) across your machines and participants in your wallet. We will also keep a backup of your wallet descriptor for you. This is the most convenient option but has privacy implications: your data would be stored on our servers (but never shared with a third party).";
|
||||
pub const REMOTE_BACKEND_DESC: &str = "Use a hosted service to talk to the Bitcoin network and store data. Wizardsardine runs the infrastructure, keeps a backup of your wallet descriptor, and allow for synchronization between multiple computers and participants.\n\nThis is a safer option for users who want Wizardsardine to keep a backup of your descriptor. Wizardsardine will be able to see the information of your wallet, associated to an email address. Privacy focused users should run their own infrastructure instead.";
|
||||
|
||||
pub const LIANA_DESC: &str = "This option creates a wallet on your machine. The wallet will never access any of our servers, we would not even be able to know you use our wallet. This option requires a local Bitcoin full node. A full node is necessary to use Bitcoin in a sovereign way, but it is more accessible than it sounds. The Liana wallet can download and run one for you so you don't have to manage it yourself. It will never use more than a couple GB of disk space. The initial synchronisation of the node takes time and is computationally intensive, but past this point running a Bitcoin full node on your machine is seamless.";
|
||||
pub const LOCAL_WALLET_DESC: &str = "Use your already existing Bitcoin node or automatically install one. The Liana wallet will not connect to any external server.\n\nThis is the most private option, but the data is locally stored on this computer, only. You must perform your own backups, and share the descriptor with other people you want to be able to access the wallet";
|
||||
|
||||
fn layout<'a>(
|
||||
progress: (usize, usize),
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user