koibumi 0.0.10

An experimental Bitmessage client
use async_std::task;
use futures::{channel::mpsc::Sender, sink::SinkExt};
use iced::{
    widget::{button, scrollable, Column, Row, Text, TextInput},
    Command, Element, Length,
};
use log::error;

use koibumi_common::boxes::{Boxes, DEFAULT_USER_ID};
use koibumi_core::address::Address;
use koibumi_node::Command as NodeCommand;

use crate::{config::Config as GuiConfig, gui};

#[derive(Clone, Debug, Default)]
pub(crate) struct Tab {
    address_value: String,
}

impl Tab {
    pub(crate) fn update(
        &mut self,
        message: gui::Message,
        boxes: &mut Option<Boxes>,
        command_sender: &mut Sender<NodeCommand>,
    ) -> Command<gui::Message> {
        if boxes.is_none() {
            return Command::none();
        }
        let boxes = boxes.as_mut().unwrap();
        match message {
            gui::Message::SubscriptionsAddressChanged(address) => {
                self.address_value = address;
                Command::none()
            }
            gui::Message::SubscriptionsSubscribePressed => {
                let address = self.address_value.parse::<Address>();
                if let Err(err) = address {
                    error!("{}", err);
                    return Command::none();
                }
                let address = address.unwrap();
                if boxes.user().subscriptions().contains(&address) {
                    return Command::none();
                }
                if let Err(err) =
                    task::block_on(boxes.manager().subscribe(DEFAULT_USER_ID, &address))
                {
                    error!("{}", err);
                    return Command::none();
                }
                if let Err(err) = task::block_on(command_sender.send(NodeCommand::Subscribe {
                    id: DEFAULT_USER_ID.to_vec(),
                    address: address.clone(),
                })) {
                    error!("{}", err);
                    return Command::none();
                }
                boxes.user_mut().subscriptions_mut().push(address);
                self.address_value = String::new();
                Command::none()
            }
            _ => panic!("Program error"),
        }
    }

    pub(crate) fn view(
        &self,
        config: &GuiConfig,
        subscriptions: &[Address],
        boxes: &Option<Boxes>,
    ) -> Element<gui::Message> {
        let text_size = config.text_size();

        if boxes.is_none() {
            return Column::new()
                .push(Text::new("inbox/outbox database error").size(text_size))
                .into();
        }
        let boxes = boxes.as_ref().unwrap();

        let mut list = Column::new();
        for address in subscriptions {
            let alias = boxes.user().rich_alias(&address.to_string());
            list = list.push(Text::new(alias).size(text_size));
        }
        let list = scrollable(list).height(Length::Fill);
        // XXX .spacing(text_size / 4);

        let subscribe = Row::new()
            .spacing(text_size / 4)
            .push(
                TextInput::new("Address", &self.address_value)
                    .on_input(gui::Message::SubscriptionsAddressChanged)
                    .size(text_size)
                    .padding(4),
            )
            .push(
                button(Text::new("Subscribe").size(text_size))
                    .on_press(gui::Message::SubscriptionsSubscribePressed),
            );

        Column::new()
            .spacing(text_size / 4)
            .push(list)
            .push(subscribe)
            .into()
    }
}