Skip to content

Commit

Permalink
refactor: split federation details page to separate file
Browse files Browse the repository at this point in the history
  • Loading branch information
tvolk131 committed Oct 12, 2024
1 parent 149a9cd commit 50e5b94
Show file tree
Hide file tree
Showing 2 changed files with 193 additions and 148 deletions.
164 changes: 16 additions & 148 deletions src/routes/bitcoin_wallet.rs
Original file line number Diff line number Diff line change
@@ -1,27 +1,26 @@
use fedimint_core::{config::FederationId, Amount};
use fedimint_core::Amount;
use iced::{
widget::{column, container::Style, horizontal_space, row, Column, Container, Space, Text},
widget::{container::Style, horizontal_space, row, Column, Container, Space, Text},
Border, Length, Shadow, Task, Theme,
};

use crate::{
app,
fedimint::{FederationView, WalletView},
ui_components::{icon_button, PaletteColor, SvgIcon, Toast, ToastStatus},
util::{format_amount, lighten, truncate_text},
ui_components::{icon_button, PaletteColor, SvgIcon},
util::{format_amount, lighten},
};

use super::{container, ConnectedState, Loadable, RouteName};

mod add;
mod federation_details;
mod receive;
mod send;

#[derive(Debug, Clone)]
pub enum Message {
LeaveFederation(FederationId),
LeftFederation(FederationId),

FederationDetails(federation_details::Message),
Add(add::Message),
Send(send::Message),
Receive(receive::Message),
Expand All @@ -37,43 +36,12 @@ pub struct Page {
impl Page {
pub fn update(&mut self, msg: Message) -> Task<app::Message> {
match msg {
Message::LeaveFederation(federation_id) => {
let wallet = self.connected_state.wallet.clone();

Task::stream(async_stream::stream! {
match wallet.leave_federation(federation_id).await {
Ok(()) => {
yield app::Message::AddToast(Toast {
title: "Left federation".to_string(),
body: "You have successfully left the federation.".to_string(),
status: ToastStatus::Good,
});

yield app::Message::Routes(super::Message::BitcoinWalletPage(
Message::LeftFederation(federation_id)
));
}
Err(err) => {
yield app::Message::AddToast(Toast {
title: "Failed to leave federation".to_string(),
body: format!("Failed to leave the federation: {err}"),
status: ToastStatus::Bad,
});
}
}
})
}
Message::LeftFederation(federation_id) => {
// A verbose way of saying "if the user is currently on the FederationDetails page and the federation ID matches the one that was just left, navigate back to the List page".
if let Subroute::FederationDetails(federation_details) = &self.subroute {
if federation_details.view.federation_id == federation_id {
return Task::done(app::Message::Routes(super::Message::Navigate(
RouteName::BitcoinWallet(SubrouteName::List),
)));
}
Message::FederationDetails(federation_details_message) => {
if let Subroute::FederationDetails(federation_details_page) = &mut self.subroute {
federation_details_page.update(federation_details_message)
} else {
Task::none()
}

Task::none()
}
Message::Add(add_message) => {
if let Subroute::Add(add_page) = &mut self.subroute {
Expand Down Expand Up @@ -132,11 +100,9 @@ impl SubrouteName {
pub fn to_default_subroute(&self, connected_state: &ConnectedState) -> Subroute {
match self {
Self::List => Subroute::List(List {}),
Self::FederationDetails(federation_view) => {
Subroute::FederationDetails(FederationDetails {
view: federation_view.clone(),
})
}
Self::FederationDetails(federation_view) => Subroute::FederationDetails(
federation_details::Page::new(federation_view.clone(), connected_state),
),
Self::Add => Subroute::Add(add::Page::new(connected_state)),
Self::Send => Subroute::Send(send::Page::new(connected_state)),
Self::Receive => Subroute::Receive(receive::Page::new(connected_state)),
Expand All @@ -146,7 +112,7 @@ impl SubrouteName {

pub enum Subroute {
List(List),
FederationDetails(FederationDetails),
FederationDetails(federation_details::Page),
Add(add::Page),
Send(send::Page),
Receive(receive::Page),
Expand All @@ -157,7 +123,7 @@ impl Subroute {
match self {
Self::List(_) => SubrouteName::List,
Self::FederationDetails(federation_details) => {
SubrouteName::FederationDetails(federation_details.view.clone())
SubrouteName::FederationDetails(federation_details.clone_view())
}
Self::Add(_) => SubrouteName::Add,
Self::Send(_) => SubrouteName::Send,
Expand Down Expand Up @@ -261,101 +227,3 @@ impl List {
container
}
}

pub struct FederationDetails {
view: FederationView,
}

impl FederationDetails {
fn view<'a>(&self) -> Column<'a, app::Message> {
let mut container = container("Federation Details")
.push(
Text::new(
self.view
.name_or
.clone()
.unwrap_or_else(|| "Unnamed Federation".to_string()),
)
.size(25),
)
.push(Text::new(format!(
"Federation ID: {}",
truncate_text(&self.view.federation_id.to_string(), 23, true)
)))
.push(Text::new(format_amount(self.view.balance)))
.push(Text::new("Gateways").size(20));

for gateway in &self.view.gateways {
let vetted_text = if gateway.vetted {
"Vetted"
} else {
"Not Vetted"
};

let column: Column<_, Theme, _> = column![
Text::new(format!(
"Gateway ID: {}",
truncate_text(&gateway.info.gateway_id.to_string(), 43, true)
)),
Text::new(format!(
"Lightning Node Alias: {}",
truncate_text(&gateway.info.lightning_alias.to_string(), 43, true)
)),
Text::new(format!(
"Lightning Node Public Key: {}",
truncate_text(&gateway.info.node_pub_key.to_string(), 43, true)
)),
Text::new(vetted_text)
];

container = container.push(
Container::new(column)
.padding(10)
.width(Length::Fill)
.style(|theme| -> Style {
Style {
text_color: None,
background: Some(lighten(theme.palette().background, 0.05).into()),
border: Border {
color: iced::Color::WHITE,
width: 0.0,
radius: (8.0).into(),
},
shadow: Shadow::default(),
}
}),
);
}

// TODO: Add a function to `Wallet` to check whether we can safely leave a federation.
// Call it here rather and get rid of `has_zero_balance`.
let has_zero_balance = self.view.balance.msats == 0;

if !has_zero_balance {
container = container.push(
Text::new("Must have a zero balance in this federation in order to leave.")
.size(20),
);
}

container = container.push(
icon_button("Leave Federation", SvgIcon::Delete, PaletteColor::Danger).on_press_maybe(
has_zero_balance.then(|| {
app::Message::Routes(super::Message::BitcoinWalletPage(
Message::LeaveFederation(self.view.federation_id),
))
}),
),
);

container = container.push(
icon_button("Back", SvgIcon::ArrowBack, PaletteColor::Background).on_press(
app::Message::Routes(super::Message::Navigate(RouteName::BitcoinWallet(
SubrouteName::List,
))),
),
);

container
}
}
177 changes: 177 additions & 0 deletions src/routes/bitcoin_wallet/federation_details.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
use std::sync::Arc;

use fedimint_core::config::FederationId;
use iced::{
widget::{column, container::Style, Column, Container, Text},
Border, Length, Shadow, Task, Theme,
};

use crate::{
app,
fedimint::{FederationView, Wallet},
routes::{self, container, ConnectedState},
ui_components::{icon_button, PaletteColor, SvgIcon, Toast, ToastStatus},
util::{format_amount, lighten, truncate_text},
};

#[derive(Debug, Clone)]
pub enum Message {
LeaveFederation(FederationId),
LeftFederation(FederationId),
}

pub struct Page {
wallet: Arc<Wallet>,
view: FederationView,
}

impl Page {
pub fn new(view: FederationView, connected_state: &ConnectedState) -> Self {
Self {
wallet: connected_state.wallet.clone(),
view,
}
}

pub fn clone_view(&self) -> FederationView {
self.view.clone()
}

// TODO: Remove these clippy allows.
#[allow(clippy::needless_pass_by_value)]
#[allow(clippy::needless_pass_by_ref_mut)]
pub fn update(&mut self, msg: Message) -> Task<app::Message> {
match msg {
Message::LeaveFederation(federation_id) => {
let wallet = self.wallet.clone();

Task::stream(async_stream::stream! {
match wallet.leave_federation(federation_id).await {
Ok(()) => {
yield app::Message::AddToast(Toast {
title: "Left federation".to_string(),
body: "You have successfully left the federation.".to_string(),
status: ToastStatus::Good,
});

yield app::Message::Routes(routes::Message::BitcoinWalletPage(
super::Message::FederationDetails(Message::LeftFederation(federation_id))
));
}
Err(err) => {
yield app::Message::AddToast(Toast {
title: "Failed to leave federation".to_string(),
body: format!("Failed to leave the federation: {err}"),
status: ToastStatus::Bad,
});
}
}
})
}
Message::LeftFederation(federation_id) => {
// A verbose way of saying "if the user is currently on the FederationDetails page and the federation ID matches the one that was just left, navigate back to the List page".
if self.view.federation_id == federation_id {
return Task::done(app::Message::Routes(routes::Message::Navigate(
routes::RouteName::BitcoinWallet(super::SubrouteName::List),
)));
}

Task::none()
}
}
}

pub fn view<'a>(&self) -> Column<'a, app::Message> {
let mut container = container("Federation Details")
.push(
Text::new(
self.view
.name_or
.clone()
.unwrap_or_else(|| "Unnamed Federation".to_string()),
)
.size(25),
)
.push(Text::new(format!(
"Federation ID: {}",
truncate_text(&self.view.federation_id.to_string(), 23, true)
)))
.push(Text::new(format_amount(self.view.balance)))
.push(Text::new("Gateways").size(20));

for gateway in &self.view.gateways {
let vetted_text = if gateway.vetted {
"Vetted"
} else {
"Not Vetted"
};

let column: Column<_, Theme, _> = column![
Text::new(format!(
"Gateway ID: {}",
truncate_text(&gateway.info.gateway_id.to_string(), 43, true)
)),
Text::new(format!(
"Lightning Node Alias: {}",
truncate_text(&gateway.info.lightning_alias.to_string(), 43, true)
)),
Text::new(format!(
"Lightning Node Public Key: {}",
truncate_text(&gateway.info.node_pub_key.to_string(), 43, true)
)),
Text::new(vetted_text)
];

container = container.push(
Container::new(column)
.padding(10)
.width(Length::Fill)
.style(|theme| -> Style {
Style {
text_color: None,
background: Some(lighten(theme.palette().background, 0.05).into()),
border: Border {
color: iced::Color::WHITE,
width: 0.0,
radius: (8.0).into(),
},
shadow: Shadow::default(),
}
}),
);
}

// TODO: Add a function to `Wallet` to check whether we can safely leave a federation.
// Call it here rather and get rid of `has_zero_balance`.
let has_zero_balance = self.view.balance.msats == 0;

if !has_zero_balance {
container = container.push(
Text::new("Must have a zero balance in this federation in order to leave.")
.size(20),
);
}

container = container.push(
icon_button("Leave Federation", SvgIcon::Delete, PaletteColor::Danger).on_press_maybe(
has_zero_balance.then(|| {
app::Message::Routes(routes::Message::BitcoinWalletPage(
super::Message::FederationDetails(Message::LeaveFederation(
self.view.federation_id,
)),
))
}),
),
);

container = container.push(
icon_button("Back", SvgIcon::ArrowBack, PaletteColor::Background).on_press(
app::Message::Routes(routes::Message::Navigate(routes::RouteName::BitcoinWallet(
super::SubrouteName::List,
))),
),
);

container
}
}

0 comments on commit 50e5b94

Please sign in to comment.