install-framework-gui 1.0.0

[Install Framework] GUI interface powered by iced
Documentation
// Copyright 2021 Yuri6037

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.

use std::vec::Vec;
use std::collections::HashSet;
use async_channel::Sender;
use async_channel::SendError;
use iced::Element;
use iced::Row;
use iced::Column;
use iced::Text;
use iced::Checkbox;
use iced::scrollable;
use iced::Align;
use iced::button;
use iced::Length;
use install_framework_base::interface::InstallationState;
use install_framework_core::interface::Component;

use super::window::Page;
use super::window::ConstructiblePage;
use super::window::PageMessage;
use crate::messages::RenderMessage;
use crate::messages::ThreadMessage;
use crate::messages;
use crate::ext::SenderSync;

pub struct HomePage
{
    available_components: Vec<Component>,
    selected_components: HashSet<usize>,
    install_state: Option<InstallationState>,
    useless: scrollable::State,
    useless1: button::State,
    useless2: scrollable::State,
    useless3: button::State,
    uninstall: bool
}

impl ConstructiblePage for HomePage
{
    type PageType = HomePage;

    fn new(msg: &messages::Page) -> HomePage
    {
        if let messages::Page::ComponentView(comps, state, uninstall) = msg
        {
            return HomePage
            {
                available_components: comps.clone(),
                selected_components: HashSet::new(),
                install_state: state.clone(),
                useless: scrollable::State::new(),
                useless1: button::State::new(),
                useless2: scrollable::State::new(),
                useless3: button::State::new(),
                uninstall: *uninstall
            };
        }
        panic!("The impossible happened: incorrect message received");
    }
}

impl Page for HomePage
{
    fn handle_message(&mut self, _: &RenderMessage, _: &mut Sender<ThreadMessage>) -> Result<(), SendError<ThreadMessage>>
    {
        return Ok(());
    }

    fn update(&mut self, msg: &PageMessage, sender: &mut Sender<ThreadMessage>) -> Result<bool, SendError<ThreadMessage>>
    {
        match msg
        {
            PageMessage::ToggleComponent(id) =>
            {
                if self.selected_components.contains(id)
                {
                    self.selected_components.remove(id);
                }
                else
                {
                    self.selected_components.insert(*id);
                }
            },
            PageMessage::Next =>
            {
                let mut comps = Vec::new();
                for i in &self.selected_components
                {
                    comps.push(self.available_components[*i].clone());
                }
                sender.send_sync(ThreadMessage::InstallComponents(comps))?;
            },
            PageMessage::Close => return Ok(true),
            _ => ()
        }
        return Ok(false);
    }

    fn view(&mut self) -> Element<PageMessage>
    {
        let mut col = Column::new().spacing(5);

        if let Some(state) = &self.install_state
        {
            col = col.push(Text::new("Installed components:"));
            let mut scroll = scrollable::Scrollable::new(&mut self.useless2).spacing(5).width(Length::Fill).max_height(140);
            for v in &state.installed_components
            {
                let mut r = Row::new().push(Text::new(&v.name));
                if let Some(v1) = &v.version
                {
                    r = r.push(Text::new("    ")).push(Text::new(v1));
                }
                scroll = scroll.push(r);
            }
            col = col.push(scroll).push(Text::new(" "));
        }
        col = col.push(Text::new("Available components:"));
        for (i, v) in self.available_components.iter().enumerate()
        {
            col = col.push(
                Checkbox::new(self.selected_components.contains(&i), &v.name, move |_| PageMessage::ToggleComponent(i))
            );
        }
        col = col.push(Text::new(" "));
        col = col.push(Text::new("Overview:"));
        let mut scroll = scrollable::Scrollable::new(&mut self.useless).spacing(5).width(Length::Fill).max_height(140);
        for i in &self.selected_components
        {
            let c = &self.available_components[*i];
            if self.uninstall
            {
                scroll = scroll.push(Text::new(format!("Uninstall {}:", c.name)));
            }
            else
            {
                scroll = scroll.push(Text::new(format!("Install {}:", c.name)));
            }
            if let Some(v) = &c.version
            {
                scroll = scroll.push(
                    Row::new()
                        .align_items(Align::Center)
                        .push(Text::new("Version: "))
                        .push(Text::new(v)
                    )
                );
            }
            if let Some(v) = &c.readme
            {
                scroll = scroll.push(Text::new("Readme:"));
                scroll = scroll.push(Text::new(v));
            }
            if let Some(v) = &c.license
            {
                scroll = scroll.push(Text::new("License:"));
                scroll = scroll.push(Text::new(v));
            }
            scroll = scroll.push(Text::new(" "));
        }
        col = col.push(scroll);
        col = col.push(Text::new(" ")).push(Text::new(" "));
        col = col.push(
            Row::new()
                .width(Length::Fill)
                .push(
                    Column::new()
                        .width(Length::Fill)
                        .align_items(Align::Start)
                        .push(button::Button::new(&mut self.useless3, Text::new("Cancel & Close")).on_press(PageMessage::Close))
                )
                .push(
                    Column::new()
                        .width(Length::Fill)
                        .align_items(Align::End)
                        .push(button::Button::new(&mut self.useless1, Text::new("Next")).on_press(PageMessage::Next))
                )
        );
        return col.into();
    }
}