impala 0.7.1

TUI for managing wifi
Documentation
use anyhow::Result;
use qrcode::QrCode;
use std::{cmp, fs};
use tui_qrcode::{Colors, QrCodeWidget};

use ratatui::{
    Frame,
    layout::{Constraint, Direction, Flex, Layout, Rect},
    style::{Color, Style, Stylize},
    text::{Line, Span, Text},
    widgets::{Block, BorderType, Borders, Clear},
};

use crate::iwd_network_name;

#[derive(Clone)]
pub struct Share {
    pub qr_code: QrCode,
    pub network_name: String,
    pub passphrase: String,
}

impl Share {
    pub fn new(network_name: String) -> Result<Self> {
        let encoded_network_name = iwd_network_name(&network_name);
        let content = fs::read_to_string(format!("/var/lib/iwd/{}.psk", encoded_network_name))?;

        if let Some(line) = content
            .lines()
            .find(|&line| line.starts_with("Passphrase="))
            && let Some((_, passphrase)) = line.split_once('=')
        {
            let message = format!("WIFI:T:WPA;S:{network_name};P:{passphrase};;");
            let qr_code = QrCode::new(message)?;
            Ok(Self {
                qr_code,
                network_name,
                passphrase: passphrase.to_string(),
            })
        } else {
            unreachable!()
        }
    }

    pub fn render(&self, frame: &mut Frame) {
        let widget = QrCodeWidget::new(self.qr_code.clone()).colors(Colors::Inverted);
        let sim_area = Rect::new(0, 0, 50, 50);
        let size = widget.size(sim_area);

        let block_width = cmp::max(size.width as usize, self.passphrase.len() + 12) + 6;

        let block = Layout::default()
            .direction(Direction::Vertical)
            .constraints([
                Constraint::Fill(1),
                Constraint::Length(size.height + 12),
                Constraint::Fill(1),
            ])
            .flex(Flex::SpaceBetween)
            .split(frame.area())[1];

        let block = Layout::default()
            .direction(Direction::Horizontal)
            .constraints([
                Constraint::Fill(1),
                Constraint::Length(block_width as u16),
                Constraint::Fill(1),
            ])
            .flex(Flex::SpaceBetween)
            .split(block)[1];

        let (title_block, mut qr_block, passphrase_block) = {
            let chunks = Layout::default()
                .direction(Direction::Vertical)
                .constraints([
                    Constraint::Length(3),
                    Constraint::Fill(1),
                    Constraint::Length(3),
                ])
                .margin(3)
                .flex(Flex::SpaceBetween)
                .split(block);

            (chunks[0], chunks[1], chunks[2])
        };

        frame.render_widget(Clear, block);
        frame.render_widget(
            Block::new()
                .borders(Borders::all())
                .border_type(BorderType::Thick)
                .border_style(Style::new().green()),
            block,
        );
        frame.render_widget(
            Text::from(self.network_name.clone()).centered().bold(),
            title_block,
        );

        if (size.width as usize) < block_width {
            qr_block = Layout::default()
                .direction(Direction::Horizontal)
                .constraints([
                    Constraint::Fill(1),
                    Constraint::Length(size.width),
                    Constraint::Fill(1),
                ])
                .flex(Flex::SpaceBetween)
                .split(qr_block)[1];
        }

        frame.render_widget(widget, qr_block);

        let passphrase = Text::from(vec![
            Line::from(""),
            Line::from(vec![
                Span::from("Passphrase: "),
                Span::from(&self.passphrase).bold().bg(Color::DarkGray),
            ])
            .centered(),
        ]);
        frame.render_widget(passphrase, passphrase_block);
    }
}