gm-tui 0.0.1

TUI-based Ethereum wallet
Documentation
use std::sync::{atomic::AtomicBool, mpsc, Arc};

use alloy::signers::SignerSync;
use ratatui::{buffer::Buffer, layout::Rect};
use strum::EnumIter;

use crate::{
    tui::{
        app::{
            widgets::form::{Form, FormItemIndex, FormWidget},
            SharedState,
        },
        events::Event,
        traits::{Component, HandleResult},
    },
    utils::account::AccountManager,
};

#[derive(EnumIter, PartialEq)]
pub enum FormItem {
    Heading,
    Message,
    SignMessageButton,
    Signature,
}

pub struct SignMessagePage {
    form: Form<FormItem>,
}
impl FormItemIndex for FormItem {
    fn index(self) -> usize {
        self as usize
    }
}
impl TryFrom<FormItem> for FormWidget {
    type Error = crate::Error;
    fn try_from(value: FormItem) -> crate::Result<Self> {
        let widget = match value {
            FormItem::Heading => FormWidget::Heading("Sign a Message"),
            FormItem::Message => FormWidget::InputBox {
                label: "Message",
                text: String::new(),
                empty_text: Some("Type message to sign"),
                currency: None,
            },
            FormItem::SignMessageButton => FormWidget::Button {
                label: "Sign Message",
            },
            FormItem::Signature => FormWidget::DisplayText(String::new()),
        };
        Ok(widget)
    }
}

impl SignMessagePage {
    pub fn new() -> crate::Result<Self> {
        Ok(Self {
            form: Form::init(|_| Ok(()))?,
        })
    }
}

impl Component for SignMessagePage {
    fn set_focus(&mut self, focus: bool) {
        self.form.set_form_focus(focus);
    }

    fn handle_event(
        &mut self,
        event: &Event,
        _area: Rect,
        _transmitter: &mpsc::Sender<Event>,
        _shutdown_signal: &Arc<AtomicBool>,
        shared_state: &SharedState,
    ) -> crate::Result<HandleResult> {
        self.form.handle_event(
            event,
            |_, _| Ok(()),
            |item, form| {
                if item == FormItem::SignMessageButton
                    && form.get_text(FormItem::Signature).is_empty()
                {
                    let message = form.get_text(FormItem::Message);

                    let wallet_address = shared_state.try_current_account()?;
                    let wallet = AccountManager::load_wallet(&wallet_address)?;
                    let signature = wallet.sign_message_sync(message.as_bytes())?;
                    *form.get_text_mut(FormItem::Signature) = format!("Signature:\n{signature}");
                }
                Ok(())
            },
        )?;
        Ok(HandleResult::default())
    }

    fn render_component(&self, area: Rect, buf: &mut Buffer, ss: &SharedState) -> Rect
    where
        Self: Sized,
    {
        self.form.render(area, buf, &ss.theme);

        area
    }
}