installer: add wallet export feature at descriptor backup step
This commit is contained in:
parent
b0e560c0b5
commit
68bb742755
@ -69,7 +69,7 @@ impl ExportModal {
|
||||
}
|
||||
ImportExportType::ImportPsbt => "psbt.psbt".into(),
|
||||
ImportExportType::ImportDescriptor => "descriptor.descriptor".into(),
|
||||
ImportExportType::ExportLabels => format!("liana-labels-{date}.csv"),
|
||||
ImportExportType::ExportLabels => format!("liana-labels-{date}.jsonl"),
|
||||
ImportExportType::ExportBackup(_) => format!("liana-backup-{date}.json"),
|
||||
}
|
||||
}
|
||||
@ -95,8 +95,12 @@ impl ExportModal {
|
||||
self.state = ImportExportState::Progress(p);
|
||||
}
|
||||
}
|
||||
Progress::Finished | Progress::Ended => self.state = ImportExportState::Ended,
|
||||
Progress::Error(e) => self.error = Some(e),
|
||||
Progress::Finished | Progress::Ended => {
|
||||
self.state = ImportExportState::Ended;
|
||||
}
|
||||
Progress::Error(e) => {
|
||||
self.error = Some(e);
|
||||
}
|
||||
Progress::None => {}
|
||||
Progress::Psbt(_) => {
|
||||
if self.import_export_type == ImportExportType::ImportPsbt {
|
||||
|
||||
@ -271,13 +271,15 @@ impl State for ImportExportSettingsState {
|
||||
},
|
||||
|s| {
|
||||
Message::View(view::Message::Settings(
|
||||
view::SettingsMessage::ExportBackup(s),
|
||||
view::SettingsMessage::ExportBackup(Ok(s)),
|
||||
))
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
Message::View(view::Message::Settings(view::SettingsMessage::ExportBackup(backup))) => {
|
||||
Message::View(view::Message::Settings(view::SettingsMessage::ExportBackup(Ok(
|
||||
backup,
|
||||
)))) => {
|
||||
let modal = ExportModal::new(Some(daemon), ImportExportType::ExportBackup(backup));
|
||||
launch!(self, modal);
|
||||
}
|
||||
|
||||
@ -240,7 +240,7 @@ impl State for WalletSettingsState {
|
||||
},
|
||||
|s| {
|
||||
Message::View(view::Message::Settings(
|
||||
view::SettingsMessage::ExportBackup(s),
|
||||
view::SettingsMessage::ExportBackup(Ok(s)),
|
||||
))
|
||||
},
|
||||
)
|
||||
@ -248,7 +248,9 @@ impl State for WalletSettingsState {
|
||||
Task::none()
|
||||
}
|
||||
}
|
||||
Message::View(view::Message::Settings(view::SettingsMessage::ExportBackup(backup))) => {
|
||||
Message::View(view::Message::Settings(view::SettingsMessage::ExportBackup(Ok(
|
||||
backup,
|
||||
)))) => {
|
||||
if self.modal.is_none() {
|
||||
let modal =
|
||||
// ExportModal::new(Some(daemon), ImportExportType::ExportBackup(backup));
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use crate::{app::menu::Menu, export::ImportExportMessage, node::bitcoind::RpcAuthType};
|
||||
use crate::{app::menu::Menu, backup, export::ImportExportMessage, node::bitcoind::RpcAuthType};
|
||||
use liana::miniscript::bitcoin::{bip32::Fingerprint, OutPoint};
|
||||
|
||||
pub trait Close {
|
||||
@ -89,7 +89,7 @@ pub enum SettingsMessage {
|
||||
ExportTransactions,
|
||||
ExportLabels,
|
||||
ExportWallet,
|
||||
ExportBackup(String),
|
||||
ExportBackup(Result<String, backup::Error>),
|
||||
ImportWallet,
|
||||
AboutSection,
|
||||
RegisterWallet,
|
||||
|
||||
@ -46,19 +46,19 @@ pub struct Backup {
|
||||
pub proprietary: serde_json::Map<String, serde_json::Value>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Error {
|
||||
DescriptorMissing,
|
||||
NotSingleWallet,
|
||||
Json,
|
||||
SettingsFromFile,
|
||||
Daemon(DaemonError),
|
||||
Daemon(String),
|
||||
TxTimeMissing,
|
||||
}
|
||||
|
||||
impl From<DaemonError> for Error {
|
||||
fn from(value: DaemonError) -> Self {
|
||||
Error::Daemon(value)
|
||||
Error::Daemon(value.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -8,6 +8,7 @@ use super::{context, Error};
|
||||
use crate::{
|
||||
app::settings::ProviderKey,
|
||||
app::view::Close,
|
||||
backup,
|
||||
download::{DownloadError, Progress},
|
||||
export::ImportExportMessage,
|
||||
hw::HardwareWalletMessage,
|
||||
@ -51,6 +52,8 @@ pub enum Message {
|
||||
RedeemNextKey,
|
||||
KeyRedeemed(ProviderKey, Result<(), services::Error>),
|
||||
AllKeysRedeemed,
|
||||
BackupWallet,
|
||||
ExportWallet(Result<String, backup::Error>),
|
||||
ImportExport(ImportExportMessage),
|
||||
}
|
||||
|
||||
@ -62,7 +65,7 @@ impl Close for Message {
|
||||
|
||||
impl From<ImportExportMessage> for Message {
|
||||
fn from(value: ImportExportMessage) -> Self {
|
||||
Self::ImportExport(value)
|
||||
Message::ImportExport(value)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -25,6 +25,7 @@ use crate::{
|
||||
settings::{self as gui_settings, AuthConfig, Settings, SettingsError, WalletSetting},
|
||||
wallet::wallet_name,
|
||||
},
|
||||
backup,
|
||||
daemon::DaemonError,
|
||||
datadir::create_directory,
|
||||
hw::{HardwareWalletConfig, HardwareWallets},
|
||||
@ -730,6 +731,7 @@ pub enum Error {
|
||||
CannotGetAvailablePort(String),
|
||||
Unexpected(String),
|
||||
HardwareWallet(async_hwi::Error),
|
||||
Backup(backup::Error),
|
||||
}
|
||||
|
||||
impl From<jsonrpc::simple_http::Error> for Error {
|
||||
@ -783,6 +785,7 @@ impl std::fmt::Display for Error {
|
||||
Self::CannotCreateFile(e) => write!(f, "Failed to create file: {}", e),
|
||||
Self::Unexpected(e) => write!(f, "Unexpected: {}", e),
|
||||
Self::HardwareWallet(e) => write!(f, "Hardware Wallet: {}", e),
|
||||
Self::Backup(e) => write!(f, "Backup: {:?}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,7 +16,9 @@ use liana_ui::{component::form, widget::Element};
|
||||
use async_hwi::DeviceKind;
|
||||
|
||||
use crate::{
|
||||
app::{settings::KeySetting, wallet::wallet_name},
|
||||
app::{settings::KeySetting, state::export::ExportModal, wallet::wallet_name},
|
||||
backup::{self, Backup},
|
||||
export::{ImportExportMessage, ImportExportType},
|
||||
hw::{HardwareWallet, HardwareWallets},
|
||||
installer::{
|
||||
message::{self, Message},
|
||||
@ -292,16 +294,71 @@ pub struct BackupDescriptor {
|
||||
done: bool,
|
||||
descriptor: Option<LianaDescriptor>,
|
||||
keys: HashMap<Fingerprint, KeySetting>,
|
||||
modal: Option<ExportModal>,
|
||||
error: Option<Error>,
|
||||
context: Option<Context>,
|
||||
}
|
||||
|
||||
impl Step for BackupDescriptor {
|
||||
fn subscription(&self, _hws: &HardwareWallets) -> Subscription<Message> {
|
||||
if let Some(modal) = &self.modal {
|
||||
if let Some(sub) = modal.subscription() {
|
||||
sub.map(|m| Message::ImportExport(ImportExportMessage::Progress(m)))
|
||||
} else {
|
||||
Subscription::none()
|
||||
}
|
||||
} else {
|
||||
Subscription::none()
|
||||
}
|
||||
}
|
||||
fn update(&mut self, _hws: &mut HardwareWallets, message: Message) -> Task<Message> {
|
||||
if let Message::UserActionDone(done) = message {
|
||||
self.done = done;
|
||||
match message {
|
||||
Message::ImportExport(ImportExportMessage::Close) => {
|
||||
self.modal = None;
|
||||
}
|
||||
Message::ImportExport(m) => {
|
||||
if let Some(modal) = self.modal.as_mut() {
|
||||
let task: Task<Message> = modal.update(m);
|
||||
return task;
|
||||
};
|
||||
}
|
||||
Message::BackupWallet => {
|
||||
if let (None, Some(ctx)) = (&self.modal, self.context.as_ref()) {
|
||||
let ctx = ctx.clone();
|
||||
return Task::perform(
|
||||
async move {
|
||||
let backup = Backup::from_installer(ctx, true).await?;
|
||||
serde_json::to_string_pretty(&backup).map_err(|_| backup::Error::Json)
|
||||
},
|
||||
Message::ExportWallet,
|
||||
);
|
||||
}
|
||||
}
|
||||
Message::ExportWallet(str) => {
|
||||
if self.modal.is_none() {
|
||||
let str = match str {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
tracing::error!("{e:?}");
|
||||
self.error = Some(Error::Backup(e));
|
||||
return Task::none();
|
||||
}
|
||||
};
|
||||
let modal = ExportModal::new(None, ImportExportType::ExportBackup(str));
|
||||
let launch = modal.launch();
|
||||
self.modal = Some(modal);
|
||||
return launch;
|
||||
}
|
||||
}
|
||||
Message::UserActionDone(done) => {
|
||||
self.done = done;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
fn load_context(&mut self, ctx: &Context) {
|
||||
self.context = Some(ctx.clone());
|
||||
if self.descriptor != ctx.descriptor {
|
||||
self.descriptor.clone_from(&ctx.descriptor);
|
||||
self.done = false;
|
||||
@ -318,13 +375,19 @@ impl Step for BackupDescriptor {
|
||||
progress: (usize, usize),
|
||||
email: Option<&'a str>,
|
||||
) -> Element<Message> {
|
||||
view::backup_descriptor(
|
||||
let content = view::backup_descriptor(
|
||||
progress,
|
||||
email,
|
||||
self.descriptor.as_ref().expect("Must be a descriptor"),
|
||||
&self.keys,
|
||||
self.error.as_ref(),
|
||||
self.done,
|
||||
)
|
||||
);
|
||||
if let Some(modal) = &self.modal {
|
||||
modal.view(content)
|
||||
} else {
|
||||
content
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -689,6 +689,7 @@ pub fn backup_descriptor<'a>(
|
||||
email: Option<&'a str>,
|
||||
descriptor: &'a LianaDescriptor,
|
||||
keys: &'a HashMap<Fingerprint, settings::KeySetting>,
|
||||
error: Option<&Error>,
|
||||
done: bool,
|
||||
) -> Element<'a, Message> {
|
||||
layout(
|
||||
@ -724,6 +725,7 @@ pub fn backup_descriptor<'a>(
|
||||
))
|
||||
.max_width(1000),
|
||||
)
|
||||
.push_maybe(error.map(|e| card::error("Failed to export backup", e.to_string())))
|
||||
.push(
|
||||
card::simple(
|
||||
Column::new()
|
||||
@ -741,10 +743,17 @@ pub fn backup_descriptor<'a>(
|
||||
),
|
||||
)
|
||||
.push(
|
||||
Row::new().push(Column::new().width(Length::Fill)).push(
|
||||
button::secondary(Some(icon::clipboard_icon()), "Copy")
|
||||
.on_press(Message::Clibpboard(descriptor.to_string())),
|
||||
),
|
||||
Row::new()
|
||||
.push(Space::with_width(Length::Fill))
|
||||
.push(
|
||||
button::secondary(Some(icon::wallet_icon()), "Backup")
|
||||
.on_press(Message::BackupWallet),
|
||||
)
|
||||
.push(Space::with_width(10))
|
||||
.push(
|
||||
button::secondary(Some(icon::clipboard_icon()), "Copy")
|
||||
.on_press(Message::Clibpboard(descriptor.to_string())),
|
||||
),
|
||||
)
|
||||
.spacing(10),
|
||||
)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user