Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 28 additions & 1 deletion liana-gui/src/app/state/export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::{
};

use iced::{Subscription, Task};
use liana_ui::component::form;
use liana_ui::{widget::modal::Modal, widget::Element};
use tokio::task::JoinHandle;

Expand All @@ -19,6 +20,7 @@ use crate::{
#[derive(Debug)]
pub struct ExportModal {
path: Option<PathBuf>,
manual_path: form::Value<String>,
handle: Option<Arc<Mutex<JoinHandle<()>>>>,
state: ImportExportState,
error: Option<export::Error>,
Expand Down Expand Up @@ -62,6 +64,7 @@ impl ExportModal {
) -> Self {
Self {
path: None,
manual_path: form::Value::default(),
handle: None,
state: ImportExportState::Init,
error: None,
Expand Down Expand Up @@ -204,7 +207,30 @@ impl ExportModal {
self.path = Some(path);
self.start();
} else {
return Task::perform(async {}, |_| ImportExportMessage::Close.into());
self.manual_path.value = match self.import_export_type {
ImportExportType::Transactions
| ImportExportType::ExportPsbt(_)
| ImportExportType::ExportEncryptedDescriptor(_)
| ImportExportType::ExportProcessBackup(..)
| ImportExportType::ExportXpub(_)
| ImportExportType::Descriptor(_)
| ImportExportType::ExportLabels => self.default_filename(),
_ => String::new(),
};
self.manual_path.valid = true;
self.state = ImportExportState::ManualPath;
}
}
ImportExportMessage::PathEdited(path) => {
self.manual_path.value = path;
self.manual_path.valid = true;
}
ImportExportMessage::ConfirmPath => {
if !self.manual_path.value.trim().is_empty() {
self.path = Some(self.manual_path.value.trim().into());
self.start();
} else {
self.manual_path.valid = false;
}
}
ImportExportMessage::Close | ImportExportMessage::Open => { /* unreachable */ }
Expand Down Expand Up @@ -289,6 +315,7 @@ impl ExportModal {
self.error.as_ref(),
self.modal_title(),
&self.import_export_type,
&self.manual_path,
),
);
match self.state {
Expand Down
36 changes: 32 additions & 4 deletions liana-gui/src/app/view/export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use iced::{
};
use liana_ui::{
component::{
button, card,
button, card, form,
text::{h4_bold, text},
},
icon,
Expand All @@ -21,6 +21,7 @@ pub fn export_modal<'a, Message: From<ImportExportMessage> + Clone + 'static>(
error: Option<&'a Error>,
title: &str,
import_export_type: &ImportExportType,
manual_path: &'a form::Value<String>,
) -> Element<'a, Message> {
let cancel = match state {
ImportExportState::Started | ImportExportState::Progress(_) => {
Expand Down Expand Up @@ -48,6 +49,9 @@ pub fn export_modal<'a, Message: From<ImportExportMessage> + Clone + 'static>(
ImportExportState::ChoosePath => {
"Select the path you want to export in the popup window...".into()
}
ImportExportState::ManualPath => {
"The file picker returned no path. Enter one manually or close this dialog.".into()
}
ImportExportState::Path(_) => "".into(),
ImportExportState::Started => "Starting export...".into(),
ImportExportState::Progress(p) => format!("Progress: {}%", p.round()),
Expand Down Expand Up @@ -103,12 +107,34 @@ pub fn export_modal<'a, Message: From<ImportExportMessage> + Clone + 'static>(
.align_x(Horizontal::Center)
.width(Length::Fill)
});
let manual_path_form = matches!(state, ImportExportState::ManualPath).then(|| {
form::Form::<Message>::new_trimmed("Path", manual_path, |path| {
Message::from(ImportExportMessage::PathEdited(path))
})
.warning("Please enter a filesystem path")
.padding(10)
});
let manual_path_actions = matches!(state, ImportExportState::ManualPath).then(|| {
Container::new(
Row::new()
.spacing(10)
.push(Space::with_width(Length::Fill))
.push(button::secondary(None, "Close").on_press(ImportExportMessage::Close.into()))
.push(
button::secondary(None, "Use path")
.on_press(ImportExportMessage::ConfirmPath.into()),
),
)
.align_x(Horizontal::Center)
.width(Length::Fill)
});

let mut p = match state {
ImportExportState::Init => 0.0,
ImportExportState::ChoosePath | ImportExportState::Path(_) | ImportExportState::Started => {
5.0
}
ImportExportState::ChoosePath
| ImportExportState::ManualPath
| ImportExportState::Path(_)
| ImportExportState::Started => 5.0,
ImportExportState::Progress(p) => *p,
ImportExportState::TimedOut
| ImportExportState::Aborted
Expand Down Expand Up @@ -138,7 +164,9 @@ pub fn export_modal<'a, Message: From<ImportExportMessage> + Clone + 'static>(
.push(progress_bar_row)
.push(Space::with_height(Length::Fill))
.push(Row::new().push(text(msg)))
.push_maybe(manual_path_form)
.push(Space::with_height(Length::Fill))
.push_maybe(manual_path_actions)
.push_maybe(button)
.push(Space::with_height(5)),
)
Expand Down
3 changes: 3 additions & 0 deletions liana-gui/src/export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ pub enum ImportExportMessage {
TimedOut,
UserStop,
Path(Option<PathBuf>),
PathEdited(String),
ConfirmPath,
Close,
Overwrite,
Ignore,
Expand All @@ -99,6 +101,7 @@ impl From<ImportExportMessage> for view::Message {
pub enum ImportExportState {
Init,
ChoosePath,
ManualPath,
Path(PathBuf),
Started,
Progress(f32),
Expand Down
44 changes: 34 additions & 10 deletions liana-gui/src/installer/step/descriptor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ pub struct ImportDescriptor {
imported_descriptor: form::Value<String>,
imported_backup: Option<Backup>,
imported_aliases: Option<HashMap<Fingerprint, KeySetting>>,
descriptor_from_backup: bool,
}

impl ImportDescriptor {
Expand All @@ -49,6 +50,7 @@ impl ImportDescriptor {
modal: ImportDescriptorModal::None,
imported_backup: None,
imported_aliases: None,
descriptor_from_backup: false,
}
}

Expand Down Expand Up @@ -78,6 +80,30 @@ impl ImportDescriptor {
None
}
}

fn clear_imported_backup(&mut self) {
self.imported_backup = None;
self.imported_aliases = None;
if self.descriptor_from_backup {
self.imported_descriptor.value.clear();
self.check_descriptor(self.network);
self.descriptor_from_backup = false;
}
}

fn set_imported_backup(
&mut self,
descriptor: LianaDescriptor,
aliases: Option<HashMap<Fingerprint, KeySetting>>,
backup: Backup,
) {
self.imported_descriptor.value = descriptor.to_string();
self.check_descriptor(self.network);
self.imported_backup = Some(backup);
self.imported_aliases = aliases;
self.descriptor_from_backup = true;
self.error = None;
}
}

impl Step for ImportDescriptor {
Expand All @@ -98,13 +124,15 @@ impl Step for ImportDescriptor {
if desc != self.imported_descriptor.value {
self.imported_backup = None;
self.imported_aliases = None;
self.descriptor_from_backup = false;
}
self.imported_descriptor.value = desc;
self.check_descriptor(self.network);
None
}
Message::ImportBackup => {
self.imported_backup = None;
self.clear_imported_backup();
self.error = None;
let modal = ExportModal::new(None, ImportExportType::FromBackup);
let launch = modal.launch(false);
self.modal = ImportDescriptorModal::Export(modal);
Expand All @@ -118,19 +146,15 @@ impl Step for ImportDescriptor {
let (descriptor, network, aliases, backup) = r;
if let Some(n) = network {
if self.network == n {
self.imported_backup = Some(backup);
self.imported_descriptor.value = descriptor.to_string();
self.imported_aliases = Some(aliases);
self.set_imported_backup(descriptor, Some(aliases), backup);
} else {
self.error = Some(BACKUP_NETWORK_NOT_MATCH.into());
}
} else {
// The backup have been inferred from a bare descriptor, we check whether
// the descriptor match any test network
if self.network != Network::Bitcoin {
self.imported_backup = Some(backup);
self.imported_descriptor.value = descriptor.to_string();
self.imported_aliases = Some(aliases);
self.set_imported_backup(descriptor, Some(aliases), backup);
} else {
self.error = Some(BACKUP_NETWORK_NOT_MATCH.into());
}
Expand Down Expand Up @@ -170,9 +194,9 @@ impl Step for ImportDescriptor {
// as non Mainnet keys / descriptor are parsed as Signet
backup.network = self.network;

self.imported_descriptor.value = desc;
self.imported_backup = Some(backup);
self.imported_aliases = None;
let descriptor = LianaDescriptor::from_str(&desc)
.expect("backup descriptor must stay valid");
self.set_imported_backup(descriptor, None, backup);
self.modal = ImportDescriptorModal::None;
} else {
self.modal = ImportDescriptorModal::None;
Expand Down
16 changes: 16 additions & 0 deletions liana-gui/src/installer/view/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,14 @@ pub fn signer_xpubs<'a>(
.width(Length::Shrink),
)
.padding(10),
)
.push(
Container::new(
button::secondary(Some(icon::clipboard_icon()), "Copy")
.on_press(Message::Clipboard(xpub.clone()))
.width(Length::Shrink),
)
.padding(10),
),
)
}))
Expand Down Expand Up @@ -517,6 +525,14 @@ pub fn hardware_wallet_xpubs<'a>(
.width(Length::Shrink),
)
.padding(10),
)
.push(
Container::new(
button::secondary(Some(icon::clipboard_icon()), "Copy")
.on_press(Message::Clipboard(xpub.clone()))
.width(Length::Shrink),
)
.padding(10),
),
)
})
Expand Down
Loading