Skip to main content

gm_lib/tui/app/pages/
token_create.rs

1use crate::disk::DiskInterface;
2use crate::network::{Network, NetworkStore, Token};
3use crate::tui::app::pages::token::TokenPage;
4use crate::tui::app::pages::Page;
5use crate::tui::app::widgets::confirm_popup::ConfirmPopup;
6use crate::tui::app::widgets::form::{Form, FormItemIndex, FormWidget};
7use crate::tui::app::SharedState;
8use crate::tui::traits::{Component, HandleResult};
9use crate::tui::Event;
10use alloy::primitives::Address;
11use ratatui::buffer::Buffer;
12use ratatui::layout::Rect;
13use std::sync::atomic::AtomicBool;
14use std::sync::mpsc::Sender;
15use std::sync::Arc;
16use strum_macros::EnumIter;
17
18#[derive(EnumIter, PartialEq)]
19pub enum FormItem {
20    Heading,
21    Name,
22    Symbol,
23    Decimals,
24    ContractAddress,
25    SaveButton,
26    RemoveButton,
27    ErrorText, //TODO: Add tokens
28}
29impl FormItemIndex for FormItem {
30    fn index(self) -> usize {
31        self as usize
32    }
33}
34impl TryFrom<FormItem> for FormWidget {
35    type Error = crate::Error;
36    fn try_from(value: FormItem) -> crate::Result<Self> {
37        let widget = match value {
38            FormItem::Heading => FormWidget::Heading("Edit Network"),
39            FormItem::Name => FormWidget::InputBox {
40                label: "Name",
41                text: String::new(),
42                empty_text: None,
43                currency: None,
44            },
45            FormItem::Symbol => FormWidget::InputBox {
46                label: "Symbol",
47                text: String::new(),
48                empty_text: None,
49                currency: None,
50            },
51            FormItem::Decimals => FormWidget::InputBox {
52                label: "Decimals",
53                text: String::new(),
54                empty_text: None,
55                currency: None,
56            },
57            FormItem::ContractAddress => FormWidget::InputBox {
58                label: "Contract Address",
59                text: String::new(),
60                empty_text: None,
61                currency: None,
62            },
63            FormItem::SaveButton => FormWidget::Button { label: "Save" },
64            FormItem::RemoveButton => FormWidget::Button { label: "Remove" },
65            FormItem::ErrorText => FormWidget::ErrorText(String::new()),
66        };
67        Ok(widget)
68    }
69}
70pub struct TokenCreatePage {
71    pub form: Form<FormItem>,
72    pub token: Token,
73    pub token_index: usize,
74    pub network: Network,
75    pub network_index: usize,
76    pub remove_popup: ConfirmPopup,
77}
78impl TokenCreatePage {
79    pub fn new(token_index: usize, network_index: usize, network: Network) -> crate::Result<Self> {
80        let token = network.tokens.get(token_index).cloned().unwrap_or_default();
81        Ok(Self {
82            form: Form::init(|form| {
83                *form.get_text_mut(FormItem::Name) = token.name.clone();
84                *form.get_text_mut(FormItem::Symbol) = token.symbol.clone();
85                *form.get_text_mut(FormItem::Decimals) = token.decimals.to_string();
86                *form.get_text_mut(FormItem::ContractAddress) = token.contract_address.to_string();
87                // if network.tokens.get(token_index).is_none() {
88                //     form.hide_item(FormItem::RemoveButton);
89                // }
90                Ok(())
91            })?,
92            token_index,
93            remove_popup: ConfirmPopup::new(
94                "Remove Token",
95                "Are you sure you want to remove this token?".to_string(),
96                "Remove",
97                "Cancel",
98            ),
99            token,
100            network,
101            network_index,
102        })
103    }
104    pub fn token(form: &Form<FormItem>) -> Token {
105        Token {
106            name: form.get_text(FormItem::Name).clone(),
107            symbol: form.get_text(FormItem::Symbol).clone(),
108            decimals: form
109                .get_text(FormItem::Decimals)
110                .parse()
111                .unwrap_or_default(),
112            contract_address: form
113                .get_text(FormItem::ContractAddress)
114                .clone()
115                .parse::<Address>()
116                .unwrap_or_default(),
117        }
118    }
119}
120impl Component for TokenCreatePage {
121    fn handle_event(
122        &mut self,
123        event: &Event,
124        area: Rect,
125        _transmitter: &Sender<Event>,
126        _shutdown_signal: &Arc<AtomicBool>,
127        _shared_state: &SharedState,
128    ) -> crate::Result<HandleResult> {
129        let mut handle_result = HandleResult::default();
130        if self.remove_popup.is_open() {
131            let r = self.remove_popup.handle_event(
132                event,
133                area,
134                || {
135                    if self.network.tokens.get(self.token_index).is_some() {
136                        self.network.tokens.remove(self.token_index);
137                        let mut config = NetworkStore::load()?;
138                        config.networks[self.network_index] = self.network.clone();
139                        config.save()?;
140                    }
141                    handle_result.page_pops = 1;
142                    handle_result.page_inserts.push(Page::Token(TokenPage::new(
143                        self.network_index,
144                        self.network.clone(),
145                    )?));
146                    handle_result.reload = true;
147                    Ok(())
148                },
149                || Ok(()),
150            )?;
151            handle_result.merge(r);
152        }
153        self.form.handle_event(
154            event,
155            |_, _| Ok(()),
156            |label, form| {
157                if label == FormItem::SaveButton {
158                    let token = Self::token(form);
159                    if self.network.tokens.get(self.token_index).is_some() {
160                        self.network.tokens[self.token_index] = token;
161                    } else {
162                        self.network.tokens.push(token);
163                    }
164
165                    let mut config = NetworkStore::load()?;
166                    config.networks[self.network_index] = self.network.clone();
167                    config.save()?;
168
169                    handle_result.page_pops = 1;
170                    handle_result.page_inserts.push(Page::Token(TokenPage::new(
171                        self.network_index,
172                        self.network.clone(),
173                    )?));
174                    handle_result.reload = true;
175                }
176                if label == FormItem::RemoveButton {
177                    self.remove_popup.open();
178                }
179
180                Ok(())
181            },
182        )?;
183        Ok(handle_result)
184    }
185    fn render_component(&self, area: Rect, buf: &mut Buffer, s: &SharedState) -> Rect
186    where
187        Self: Sized,
188    {
189        self.form.render(area, buf, &s.theme);
190        self.remove_popup.render(area, buf, &s.theme.popup());
191        area
192    }
193}