diff --git a/src/kira_color_bar.rs b/src/kira_color_bar.rs new file mode 100644 index 0000000..0f8c399 --- /dev/null +++ b/src/kira_color_bar.rs @@ -0,0 +1,24 @@ +use iced::widget::{Row, container, text}; +use iced::{Alignment, Color, Element, Length}; + +// Assuming your Item struct or type implements Display or has a text representation +pub fn color_bar( + maybe_items: Option>, + bar_height: u32, +) -> Element<'static, Message> { + let mut c_b = Row::new().height(bar_height); + + if let Some(items) = maybe_items { + for (bar_text, bar_fill, bar_color) in items { + c_b = c_b.push( + container(text(bar_text).color(Color::BLACK).size(iced::Pixels(14.0))) + .height(Length::Fill) + .width(Length::FillPortion(bar_fill)) + .style(move |_| container::background(bar_color)) + .align_x(Alignment::Center) + .align_y(Alignment::Center), + ); + } + } + c_b.into() +} diff --git a/src/kira_disk_layout.rs b/src/kira_disk_layout.rs deleted file mode 100644 index 3ea399f..0000000 --- a/src/kira_disk_layout.rs +++ /dev/null @@ -1,76 +0,0 @@ -use std::fmt::Display; -use std::collections::HashMap; -use iced::widget::{Column, button, container, scrollable, text}; -use iced::{Alignment, Color, Element, Length, Theme}; - - -fn colors_map() -> HashMap { - HashMap::from([ - ("vfat".into(), Color::from_rgb8(204,121,167)), - ("xfs".into(), Color::from_rgb8(0,158,115)), - ("crypto_LUKS".into(), Color::from_rgb8(240,228,66)), - ("swap".into(), Color::from_rgb8(213,94,0)), - ("ext4".into(), Color::from_rgb8(0,114,178)), - ("btrfs".into(), Color::from_rgb8(86,180,233)), - ("other".into(), Color::from_rgb8(230,159,0)), - ]) -} - - -fn selected_button_style(theme: &Theme, status: button::Status) -> button::Style { - use iced::{Border, border::Radius}; - - //let palette = theme.palette(); - - let mut res_stile = button::primary(theme, button::Status::Active); - - - match status { - button::Status::Hovered => { - res_stile.border = Border { - color: Color::from_rgb(0.8, 0.3, 0.3), - width: 1.0, - radius: Radius::new(5.0), - }; - }, - _ => (), - } - - return res_stile; -} - - - - -// Assuming your Item struct or type implements Display or has a text representation -pub fn list_view( - items: &Vec<(T, f32, Color)>, -) -> Element<'_> { - let mut column = Column::new() - .spacing(2) - .align_x(Alignment::Center) - .width(Length::Fill); - - for (index, value) in items.iter().enumerate() { - // Create a row for each item, possibly with buttons or other controls - let list_item = if let Some(id) = selected_id - && id == index - { - button(text(value.to_string())).style(selected_button_style) - } else { - button(text(value.to_string())).style(unselected_button_style) - }; - let list_item = list_item - .width(Length::Fill) - .on_press(ListViewMessage::Select(index)); - - column = column.push(list_item); - } - - // Wrap the column in a scrollable widget - container(scrollable(column).width(Length::Fill).spacing(5)) - .style(container::bordered_box) - .height(container_height) - .padding(5) - .into() -} diff --git a/src/locales/en.json b/src/locales/en.json index 1c5d188..26df0b1 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -35,5 +35,8 @@ "partition.select_swapmode_placeholder": "Select Swap Mode", "partition.select_swapmode": "Select swap partition mode", "partition.use_zram": "Use zram technology", - "partition.use_secure_boot": "Setup secure boot" + "partition.use_secure_boot": "Setup secure boot", + "partition.current_dev_layout": "Current device layout", + "partition.current_after_install": "After installation device will look like this" + } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index e47b494..1b9c877 100644 --- a/src/main.rs +++ b/src/main.rs @@ -34,7 +34,7 @@ use crate::stages::welcome::WelcomeStage; rust_i18n::i18n!("src/locales", fallback = "en"); mod kira_theming; mod kira_scroll_list; -//mod kira_disk_layout; +mod kira_color_bar; mod stage; mod stages; diff --git a/src/stages/partition/mod.rs b/src/stages/partition/mod.rs index cb1dd06..2503387 100644 --- a/src/stages/partition/mod.rs +++ b/src/stages/partition/mod.rs @@ -20,9 +20,13 @@ use crate::stage::{ConfigValue, StageAction, StageResult}; -use iced::{Alignment, Color, Length, widget::{self, container}}; +use iced::{ + Alignment, Color, Length, + widget, +}; use rust_i18n::t; use std::collections::HashMap; +use crate::kira_color_bar; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum SwapMode { @@ -55,7 +59,7 @@ pub struct BlkDev { impl std::fmt::Display for BlkDev { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{} ({}MB)", &self.name, self.size_mb) + write!(f, "{} ({})", &self.name, size_mb_to_text(self.size_mb)) } } @@ -70,6 +74,76 @@ impl BlkDev { } } +fn part_type_to_color(t: &str) -> Color { + match t { + "vfat" => Color::from_rgb8(204, 121, 167), + "xfs" => Color::from_rgb8(0, 158, 115), + "crypto_LUKS" => Color::from_rgb8(240, 228, 66), + "swap" => Color::from_rgb8(213, 94, 0), + "ext4" => Color::from_rgb8(0, 114, 178), + "btrfs" => Color::from_rgb8(86, 180, 233), + _ => Color::from_rgb8(230, 159, 0), + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct PartInfo { + name: String, + part_type: String, + size_mb: u64, +} + +fn size_mb_to_text(size_mb: u64) -> String { + let mut s = size_mb; + if s < 1000 { + format!("{}MB", s) + } else { + s = s / 1024; + if s < 1000 { + format!("{}GB", s) + } else { + s = s / 1024; + format!("{}TB", s) + } + } +} + +impl std::fmt::Display for PartInfo { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{} {} {}", + &self.name, + self.part_type, + size_mb_to_text(self.size_mb) + ) + } +} + +impl PartInfo { + pub fn from_vect(v: &Vec) -> Option { + if v.len() == 4 && v[3] == "part" { + let name = v[0].clone(); + let size_mb = u64::from_str_radix(&v[1], 10).unwrap_or(0) / 1048576; + let part_type = v[2].clone(); + Some(Self { + name: name, + part_type: part_type, + size_mb: size_mb, + }) + } else { + None + } + } + + pub fn to_ct_params(&self, dev_size_mb: u64) -> (String, u16, Color) { + let fill_ratio: u16 = ((self.size_mb as f32 / dev_size_mb as f32) * 12.0) as u16; + let fill_ratio = fill_ratio.max(1); + let part_color = part_type_to_color(&self.part_type); + (self.to_string(), fill_ratio, part_color) + } +} + #[derive(Debug, Clone)] pub struct PartitionStage { device: Option, @@ -77,8 +151,7 @@ pub struct PartitionStage { swap_mode: Option, use_zram: bool, secure_boot: bool, - min_disk_size_mb: u64, - selected_disk_partitions: Option>, + selected_disk_parts: Option>, } #[derive(Debug, Clone)] @@ -125,21 +198,23 @@ pub fn get_disks_info_blocking() -> Result, String> { } } - -pub fn get_dev_part_blocking(dev_name: &str) -> Result, String> { - - fn part_from_vect(v: &Vec) -> (String, String, u64) { - let name = v[0].clone(); - let size_mb = u64::from_str_radix(&v[1], 10).unwrap_or(0) / 1048576; - let part_type = v[2].clone(); - (name, part_type, size_mb) - } - +/// getting list of device partitions +pub fn get_dev_part_blocking(dev_name: &str) -> Result, String> { use std::process::Command; //"lsblk -o NAME,SIZE,FSTYPE -l -n /dev/nvme0n1" - - match Command::new("lsblk").args(["-o", "NAME,SIZE,FSTYPE,TYPE", "-l", "-n", "-b", format!("/dev/{}", dev_name).as_str()]).output() { + + match Command::new("lsblk") + .args([ + "-o", + "NAME,SIZE,FSTYPE,TYPE", + "-l", + "-n", + "-b", + format!("/dev/{}", dev_name).as_str(), + ]) + .output() + { Ok(cmd_output) => { if cmd_output.status.success() { match String::from_utf8(cmd_output.stdout) { @@ -150,9 +225,7 @@ pub fn get_dev_part_blocking(dev_name: &str) -> Result>() }) - .map(|v| {println!("{:?}", &v); v}) - .filter(|l_v| l_v.len() ==4 && l_v[3] == "part") - .map(|l_v| part_from_vect(&l_v)) + .filter_map(|v| PartInfo::from_vect(&v)) .collect()), Err(ex) => Err(format!( "Exception while converting partition info to UTF8 {}", @@ -170,20 +243,35 @@ pub fn get_dev_part_blocking(dev_name: &str) -> Result HashMap { - HashMap::from([ - ("vfat".into(), Color::from_rgb8(204,121,167)), - ("xfs".into(), Color::from_rgb8(0,158,115)), - ("crypto_LUKS".into(), Color::from_rgb8(240,228,66)), - ("swap".into(), Color::from_rgb8(213,94,0)), - ("ext4".into(), Color::from_rgb8(0,114,178)), - ("btrfs".into(), Color::from_rgb8(86,180,233)), - ("other".into(), Color::from_rgb8(230,159,0)), - ]) -} + use toml::Table; impl PartitionStage { + + pub fn gen_disk_layout_estimate(&self) -> Vec { + let dev = self.device.clone().unwrap(); + let swap_size: u64 = match self.swap_mode { + Some(SwapMode::NoSwap) => 0, + Some(SwapMode::SwapHibernate) => 666, + Some(SwapMode::SwapNoHibernate) => 1024, + _ => 1024 + }; + let mut res: Vec = Vec::new(); + // UEFI partition + res.push(PartInfo { name: "EFI".into(), part_type: "vfat".into(), size_mb: 256 }); + // boot A and B + res.push(PartInfo { name: "kira_boot_a".into(), part_type: "xfs".into(), size_mb: 512 }); + res.push(PartInfo { name: "kira_boot_b".into(), part_type: "xfs".into(), size_mb: 512 }); + // user data + res.push(PartInfo { name: "kira_data".into(), part_type: "xfs".into(), size_mb: dev.size_mb - 1024 - 256 - swap_size }); + // swap + if swap_size > 0 { + res.push(PartInfo { name: "".into(), part_type: "swap".into(), size_mb: swap_size }); + } + + res + } + pub fn new(toml_config: &Table) -> Result { let maybe_dev_list = get_disks_info_blocking(); @@ -210,8 +298,7 @@ impl PartitionStage { swap_mode: Some(SwapMode::SwapNoHibernate), use_zram: true, secure_boot: false, - min_disk_size_mb: min_disk_size_mb, - selected_disk_partitions: None, + selected_disk_parts: None, }) } Err(ex) => Err(ex), @@ -254,14 +341,13 @@ impl PartitionStage { pub fn update(&mut self, message: Message) -> StageAction { match message { Message::SelectDevice(dev) => { - - self.selected_disk_partitions = match get_dev_part_blocking(&dev.name) { - Ok(dev_parts) => Some(dev_parts.iter().map(|(p_name, p_type, p_size)| { - let fill_ratio: u16 = ((*p_size as f32 / dev.size_mb as f32) * 15.0) as u16; - let fill_ratio = fill_ratio.max(2); - let p_clor = part_colors_map()[p_type]; - let p_text = format!("{} {} {}", p_name, p_type, p_size); - (p_text, fill_ratio, p_clor)}).collect()), + self.selected_disk_parts = match get_dev_part_blocking(&dev.name) { + Ok(dev_parts) => Some( + dev_parts + .iter() + .map(|part_inf| part_inf.to_ct_params(dev.size_mb)) + .collect(), + ), Err(ex) => { println!("Error getting dev partitions info: {}", ex); None @@ -289,23 +375,34 @@ impl PartitionStage { } pub fn view(&self) -> iced::Element<'_, Message> { + let dev_parts_es: Option> = if self.selected_disk_parts.is_some() { + Some(self.gen_disk_layout_estimate().iter() + .map(|part_inf| part_inf.to_ct_params(self.device.clone().unwrap().size_mb)) + .collect()) + } + else { + None + }; + + let dev_parts_text = match dev_parts_es { + Some(_) => widget::text(t!("partition.current_after_install")), + None => widget::text("") + }; + let dev_parts_content = kira_color_bar::color_bar(dev_parts_es, 48); + let dev_parts_content = widget::column![dev_parts_text, dev_parts_content]; + + + let back_button = widget::button(widget::text(t!("button.back"))).on_press(Message::Back); let next_button = widget::button(widget::text(t!("button.next"))).on_press(Message::Next); + let selected_dev_text = match self.selected_disk_parts { + Some(_) => widget::text(t!("partition.current_dev_layout")), + None => widget::text("") + }; + let selected_dev_content = kira_color_bar::color_bar(self.selected_disk_parts.clone(), 48); + let selected_dev_content = widget::column![selected_dev_text, selected_dev_content]; - - let mut selected_dev_content = widget::Row::new().height(48); - if let Some(dev_cont) = &self.selected_disk_partitions { - for part_info in dev_cont { - selected_dev_content = selected_dev_content.push( - widget::container(widget::text(&part_info.0).color(Color::BLACK)) - .height(Length::Fill).width(Length::FillPortion(part_info.1)) - .style(|_| container::background(part_info.2)) - .align_x(Alignment::Center).align_y(Alignment::Center) - ); - } - } - widget::column![ widget::container( widget::column![ @@ -333,7 +430,8 @@ impl PartitionStage { widget::checkbox(self.secure_boot) .label(t!("partition.use_secure_boot")) .on_toggle(Message::ToggleSecureBoot), - widget::container(selected_dev_content).style(widget::container::bordered_box), + selected_dev_content, + dev_parts_content, ] .padding(10) .spacing(10) @@ -341,7 +439,7 @@ impl PartitionStage { ) .height(iced::Length::Fill) .width(iced::Length::Fill) - .align_x(Alignment::Center) + .align_x(Alignment::Start) .align_y(Alignment::Center), widget::row![ back_button,