diff --git a/assets/icons/copy.svg b/assets/icons/copy.svg
new file mode 100644
index 0000000..f2cc9df
--- /dev/null
+++ b/assets/icons/copy.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/src/bridge.rs b/src/bridge.rs
index 842cabf..f8cc574 100644
--- a/src/bridge.rs
+++ b/src/bridge.rs
@@ -15,6 +15,8 @@ pub enum CoreUIMsg {
Sending,
SendSuccess,
SendFailure(String),
+ ReceiveInvoiceGenerating,
+ ReceiveInvoiceGenerated(Bolt11Invoice),
ReceiveSuccess,
ReceiveFailed(String),
BalanceUpdated(Amount),
diff --git a/src/components/button.rs b/src/components/button.rs
index cffc5bd..e07e923 100644
--- a/src/components/button.rs
+++ b/src/components/button.rs
@@ -20,6 +20,7 @@ pub enum SvgIcon {
Settings,
Squirrel,
UpRight,
+ Copy,
}
fn map_icon(icon: SvgIcon) -> Svg<'static, Theme> {
@@ -33,6 +34,7 @@ fn map_icon(icon: SvgIcon) -> Svg<'static, Theme> {
SvgIcon::Settings => Svg::from_path("assets/icons/settings.svg"),
SvgIcon::Squirrel => Svg::from_path("assets/icons/squirrel.svg"),
SvgIcon::UpRight => Svg::from_path("assets/icons/up_right.svg"),
+ SvgIcon::Copy => Svg::from_path("assets/icons/copy.svg"),
}
}
diff --git a/src/core.rs b/src/core.rs
index c252e98..ef9daa8 100644
--- a/src/core.rs
+++ b/src/core.rs
@@ -224,8 +224,17 @@ pub fn run_core() -> Subscription {
}
}
UICoreMsg::Receive(amount) => {
- if let Err(e) = core.receive(amount).await {
- error!("Error receiving: {e}");
+ core.msg(CoreUIMsg::ReceiveInvoiceGenerating).await;
+ match core.receive(amount).await {
+ Err(e) => {
+ core.msg(CoreUIMsg::ReceiveFailed(e.to_string())).await;
+ }
+ Ok(invoice) => {
+ core.msg(CoreUIMsg::ReceiveInvoiceGenerated(
+ invoice.clone(),
+ ))
+ .await;
+ }
}
}
}
diff --git a/src/main.rs b/src/main.rs
index b5decea..48c35a2 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,13 +1,14 @@
use core::run_core;
use fedimint_core::Amount;
use fedimint_ln_common::lightning_invoice::Bolt11Invoice;
+use routes::Route;
use std::str::FromStr;
use std::sync::Arc;
use bridge::CoreUIMsg;
use iced::subscription::Subscription;
use iced::widget::row;
-use iced::{program, Color};
+use iced::{clipboard, program, Color};
use iced::{Alignment, Element};
use iced::{Command, Font};
@@ -46,6 +47,10 @@ pub struct HarborWallet {
transfer_amount_str: String,
send_status: SendStatus,
send_failure_reason: Option,
+ receive_failure_reason: Option,
+ receive_status: ReceiveStatus,
+ receive_amount_str: String,
+ receive_invoice: Option,
}
impl Default for HarborWallet {
@@ -54,21 +59,19 @@ impl Default for HarborWallet {
}
}
-#[derive(Default, PartialEq, Debug, Clone, Copy)]
-pub enum Route {
+#[derive(Default, Debug, Clone)]
+enum SendStatus {
#[default]
- Home,
- Mints,
- Transfer,
- History,
- Settings,
+ Idle,
+ Sending,
}
#[derive(Default, Debug, Clone)]
-enum SendStatus {
+enum ReceiveStatus {
#[default]
Idle,
- Sending,
+ Generating,
+ WaitingToReceive,
}
#[derive(Debug, Clone)]
@@ -78,10 +81,13 @@ pub enum Message {
// Local state changes
Navigate(Route),
TransferAmountChanged(String),
+ ReceiveAmountChanged(String),
+ CopyToClipboard(String),
// Async commands we fire from the UI to core
Noop,
Send(u64),
Receive(u64),
+ GenerateInvoice,
// Core messages we get from core
CoreMessage(CoreUIMsg),
}
@@ -93,8 +99,12 @@ impl HarborWallet {
balance: Amount::ZERO,
active_route: Route::Home,
transfer_amount_str: String::new(),
+ receive_amount_str: String::new(),
send_status: SendStatus::Idle,
send_failure_reason: None,
+ receive_failure_reason: None,
+ receive_status: ReceiveStatus::Idle,
+ receive_invoice: None,
}
}
@@ -145,6 +155,10 @@ impl HarborWallet {
self.transfer_amount_str = amount;
Command::none()
}
+ Message::ReceiveAmountChanged(amount) => {
+ self.receive_amount_str = amount;
+ Command::none()
+ }
// Async commands we fire from the UI to core
Message::Noop => Command::none(),
Message::Send(_amount) => match self.send_status {
@@ -169,6 +183,27 @@ impl HarborWallet {
})
}
},
+ Message::GenerateInvoice => match self.receive_status {
+ ReceiveStatus::Generating => Command::none(),
+ _ => {
+ self.receive_failure_reason = None;
+ match self.receive_amount_str.parse::() {
+ Ok(amount) => Command::perform(
+ Self::async_receive(self.ui_handle.clone(), amount),
+ |_| Message::Noop,
+ ),
+ Err(e) => {
+ self.receive_amount_str = String::new();
+ eprintln!("Error parsing amount: {e}");
+ Command::none()
+ }
+ }
+ }
+ },
+ Message::CopyToClipboard(s) => {
+ println!("Copying to clipboard: {s}");
+ clipboard::write(s)
+ }
// Handle any messages we get from core
Message::CoreMessage(msg) => match msg {
CoreUIMsg::Sending => {
@@ -195,6 +230,16 @@ impl HarborWallet {
self.balance = balance;
Command::none()
}
+ CoreUIMsg::ReceiveInvoiceGenerating => {
+ self.receive_status = ReceiveStatus::Generating;
+ Command::none()
+ }
+ CoreUIMsg::ReceiveInvoiceGenerated(invoice) => {
+ self.receive_status = ReceiveStatus::WaitingToReceive;
+ println!("Received invoice: {invoice}");
+ self.receive_invoice = Some(invoice);
+ Command::none()
+ }
},
}
}
@@ -202,15 +247,12 @@ impl HarborWallet {
fn view(&self) -> Element {
let sidebar = crate::components::sidebar(self);
- let home_content = crate::routes::home(self);
- let mints_content = crate::routes::mints(self);
- let transfer_content = crate::routes::transfer(self);
-
let active_route = match self.active_route {
- Route::Home => home_content,
- Route::Mints => mints_content,
- Route::Transfer => transfer_content,
- _ => home_content,
+ Route::Home => crate::routes::home(self),
+ Route::Mints => crate::routes::mints(self),
+ Route::Transfer => crate::routes::transfer(self),
+ Route::Receive => crate::routes::receive(self),
+ _ => crate::routes::home(self),
};
row![sidebar, active_route]
diff --git a/src/routes/home.rs b/src/routes/home.rs
index cbdd184..b2bfcda 100644
--- a/src/routes/home.rs
+++ b/src/routes/home.rs
@@ -5,10 +5,14 @@ use iced::{Alignment, Element};
use crate::{HarborWallet, Message};
+use super::Route;
+
pub fn home(harbor: &HarborWallet) -> Element {
let balance = text(format!("{} sats", harbor.balance.sats_round_down())).size(64);
let send_button = h_button("Send", SvgIcon::UpRight).on_press(Message::Send(100));
- let receive_button = h_button("Receive", SvgIcon::DownLeft).on_press(Message::Receive(100));
+ // let receive_button = h_button("Receive", SvgIcon::DownLeft).on_press(Message::Receive(100));
+ let receive_button =
+ h_button("Receive", SvgIcon::DownLeft).on_press(Message::Navigate(Route::Receive));
let buttons = row![send_button, receive_button].spacing(32);
let failure_message = harbor
diff --git a/src/routes/mod.rs b/src/routes/mod.rs
index a103c35..c8bc64b 100644
--- a/src/routes/mod.rs
+++ b/src/routes/mod.rs
@@ -6,3 +6,17 @@ pub use mints::*;
pub mod transfer;
pub use transfer::*;
+
+pub mod receive;
+pub use receive::*;
+
+#[derive(Default, PartialEq, Debug, Clone, Copy)]
+pub enum Route {
+ #[default]
+ Home,
+ Mints,
+ Transfer,
+ History,
+ Settings,
+ Receive,
+}
diff --git a/src/routes/receive.rs b/src/routes/receive.rs
new file mode 100644
index 0000000..5c8117d
--- /dev/null
+++ b/src/routes/receive.rs
@@ -0,0 +1,34 @@
+use iced::widget::{column, container, scrollable, text, text_input};
+use iced::Length;
+use iced::{Alignment, Element};
+
+use crate::components::{h_button, SvgIcon};
+use crate::{HarborWallet, Message};
+
+pub fn receive(harbor: &HarborWallet) -> Element {
+ let col = if let Some(invoice) = harbor.receive_invoice.as_ref() {
+ column![
+ "Here's an invoice!",
+ text(format!("{invoice}")).size(16),
+ h_button("Copy to clipboard", SvgIcon::Copy)
+ .on_press(Message::CopyToClipboard(invoice.to_string())),
+ ]
+ } else {
+ column![
+ "How much do you want to receive?",
+ text_input("how much?", &harbor.receive_amount_str)
+ .on_input(Message::ReceiveAmountChanged),
+ h_button("Generate Invoice", SvgIcon::DownLeft).on_press(Message::GenerateInvoice),
+ ]
+ };
+
+ container(
+ scrollable(
+ col.spacing(32)
+ .align_items(Alignment::Center)
+ .width(Length::Fill),
+ )
+ .height(Length::Fill),
+ )
+ .into()
+}