Compare commits

...
2 Commits
Author SHA256 Message Date
kira fa5c3d3aec Refactor of stages results handling 2026-09-25 17:33:10 +02:00
kira dda9288e23 Sawing progress 2026-09-10 14:34:13 +02:00
17 changed files with 1715 additions and 1052 deletions
Generated
+807 -544
View File
File diff suppressed because it is too large Load Diff
+7 -2
View File
@@ -8,7 +8,8 @@ edition = "2024"
[dependencies] [dependencies]
blocking = "1.6" blocking = "1.6"
iced = { version = "0.14", default-features = false, features = ["crisp", "linux-theme-detection", "tiny-skia", "x11", "smol", "image"] } iced = { version = "0.14", default-features = false, features = ["crisp", "linux-theme-detection", "tiny-skia", "wgpu", "x11", "smol", "image"] }
#iced = { git = "https://github.com/iced-rs/iced", branch = "vello_cpu", default-features = false, features = ["crisp", "linux-theme-detection", "vello-cpu", "x11", "smol", "image"]}
iced_moving_picture = "0" iced_moving_picture = "0"
log = "0.4" log = "0.4"
rust-i18n = "3" rust-i18n = "3"
@@ -29,6 +30,10 @@ lto = true
debug = false debug = false
incremental = false incremental = false
codegen-units = 1 codegen-units = 1
opt-level = 3 # We need level 3 for tiny-skia otherwise render is lagging
opt-level = "s"
strip = true strip = true
[registry]
global-min-publish-age = "14 days"
+33 -200
View File
@@ -108,7 +108,27 @@ impl BlkDev {
} }
pub fn from_sys(name: &str) -> Option<Self> { pub fn from_sys(name: &str) -> Option<Self> {
Self::list_sys_blk_dev().ok()?.iter().find(|v| v.name == name).cloned() Self::list_sys_blk_dev()
.ok()?
.iter()
.find(|v| v.name == name)
.cloned()
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BcachefsProp {
pub password: Option<String>,
pub comp_alg: Option<String>,
}
impl BcachefsProp {
pub fn new(password: Option<String>, comp_alg: Option<String>) -> Self {
Self { password:password, comp_alg: comp_alg }
}
pub fn default() -> Self {
Self { password: None, comp_alg: None }
} }
} }
@@ -121,7 +141,7 @@ pub enum FSType {
SWAP, SWAP,
EXT4, EXT4,
BTRFS, BTRFS,
BCACHEFS, BCACHEFS(BcachefsProp),
UNKNOWN, UNKNOWN,
} }
@@ -134,7 +154,7 @@ impl std::fmt::Display for FSType {
Self::SWAP => write!(f, "swap"), Self::SWAP => write!(f, "swap"),
Self::EXT4 => write!(f, "ext4"), Self::EXT4 => write!(f, "ext4"),
Self::BTRFS => write!(f, "btrfs"), Self::BTRFS => write!(f, "btrfs"),
Self::BCACHEFS => write!(f, "bcachefs"), Self::BCACHEFS(_) => write!(f, "bcachefs"),
Self::UNKNOWN => write!(f, "unknown"), Self::UNKNOWN => write!(f, "unknown"),
} }
} }
@@ -150,7 +170,7 @@ impl FSType {
"swap" => Self::SWAP, "swap" => Self::SWAP,
"ext4" => Self::EXT4, "ext4" => Self::EXT4,
"btrfs" => Self::BTRFS, "btrfs" => Self::BTRFS,
"bcachefs" => Self::BCACHEFS, "bcachefs" => Self::BCACHEFS(BcachefsProp::default()),
_ => Self::UNKNOWN, _ => Self::UNKNOWN,
} }
} }
@@ -165,7 +185,7 @@ impl FSType {
Self::EXT4 => "ext4", Self::EXT4 => "ext4",
Self::BTRFS => "btrfs", Self::BTRFS => "btrfs",
// workaroud as parted do not support bcachefs partition type // workaroud as parted do not support bcachefs partition type
Self::BCACHEFS => "bcachefs", Self::BCACHEFS(_) => "xfs",
// lets do something generic here instead of panic // lets do something generic here instead of panic
Self::UNKNOWN => "linux-swap", Self::UNKNOWN => "linux-swap",
} }
@@ -188,10 +208,7 @@ impl FSType {
pub enum PartRole { pub enum PartRole {
EFI, EFI,
ROOT, ROOT,
HOME, SWAP
SWAP,
LuksRoot,
LuksHome,
} }
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
@@ -231,6 +248,10 @@ impl PartInfo {
role: None, role: None,
}) })
} }
pub fn partlabel_dev(&self) -> Option<String> {
self.gpt_label.as_ref().and_then(|l| Some(format!("/dev/disk/by-partlabel/{}", l)))
}
} }
/// getting list of device partitions /// getting list of device partitions
@@ -406,7 +427,7 @@ impl PartLayout {
self.add_part(p_size, fs_type, gpt_label, fs_label, mount_point, role) self.add_part(p_size, fs_type, gpt_label, fs_label, mount_point, role)
} }
pub fn gen_kira_layout(dev: BlkDev, efi_size: KiraSize, swap_size: KiraSize) -> Self { pub fn gen_kira_layout(dev: BlkDev, efi_size: KiraSize, swap_size: KiraSize, maybe_password: Option<String>, maybe_compr: Option<String>) -> Self {
let mut res: PartLayout = PartLayout::new(dev); let mut res: PartLayout = PartLayout::new(dev);
// UEFI partition // UEFI partition
@@ -416,12 +437,12 @@ impl PartLayout {
FSType::VFAT, FSType::VFAT,
Some("bee-efi".into()), Some("bee-efi".into()),
Some("EFI".into()), Some("EFI".into()),
Some("/efi".into()), Some("/beefi".into()),
Some(PartRole::EFI), Some(PartRole::EFI),
) )
.add_part_reserve( .add_part_reserve(
swap_size, swap_size,
FSType::BTRFS, FSType::BCACHEFS(BcachefsProp::new(maybe_password, maybe_compr)),
Some("bee-root".into()), Some("bee-root".into()),
None, None,
Some("/".into()), Some("/".into()),
@@ -444,194 +465,6 @@ impl PartLayout {
} }
} }
/// Executes parted command with given arguments
fn exec_parted(args: &Vec<&str>) -> Result<String, String> {
use std::process::Command;
match Command::new("parted").args(args).output() {
Err(ex) => Err(ex.to_string()),
Ok(out) => {
if out.status.success() {
String::from_utf8(out.stdout).map_err(|ex| ex.to_string())
} else {
Err(out.status.to_string())
}
}
}
}
fn parted_get_last_part_num(dev: &BlkDev) -> Result<u32, String> {
// parted -m /dev/loop0 print
match exec_parted(&vec!["-m", dev.full_name().as_str(), "print"]) {
Ok(res) => {
match res.lines().last().and_then(|last_line| {
last_line
.split_once(':')
.and_then(|(first_part, _)| u32::from_str_radix(first_part, 10).ok())
}) {
Some(n) => Ok(n),
None => Err("Error parsing parted output".to_string()),
}
}
Err(ex) => Err(ex),
}
}
/// init gpt partition table
/// parted --script $install_device mklabel gpt
/// Its blocking function
pub fn parted_init_gpt_part_table(dev: &BlkDev) -> Result<(), String> {
exec_parted(&vec![
"--script",
dev.full_name().as_str(),
"mklabel",
"gpt",
])
.map(|_| ())
}
const LINUX_ROOT_X86_64_TYPE: &str = "4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709";
/// creating partition from PartInfo specification
/// It assumes that we add partitions sequentially to empty space (for part attributes settings)
/// Otherwise can produce bonkers layout
pub fn parted_mkpart(dev: &BlkDev, part: &PartInfo) -> Result<(), String> {
let part_end = part.start + part.size;
// gpt label should be in double qutes
let gpt_label = if let Some(s) = &part.gpt_label {
format!("\"{}\"", s)
} else {
"\"\"".to_string()
};
// creating partition
exec_parted(&vec![
"--script",
dev.full_name().as_str(),
"mkpart",
gpt_label.as_str(),
part.fs_type.to_parted_str(),
part.start.to_parted_bytes_str().as_str(),
part_end.to_parted_bytes_str().as_str(),
])?;
// set partition options depending on its role
if let Some(role) = &part.role {
// getting part number of last created partition (hopefully)
let part_id = parted_get_last_part_num(dev)?;
match role {
PartRole::EFI => {
exec_parted(&vec![
"--script",
dev.full_name().as_str(),
"set",
&part_id.to_string(),
"esp",
"on",
])?;
}
// parted --script $install_device type 3 4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709
PartRole::ROOT => {
exec_parted(&vec![
"--script",
dev.full_name().as_str(),
"type",
&part_id.to_string(),
LINUX_ROOT_X86_64_TYPE,
])?;
}
_ => (),
}
};
Ok(())
}
/// creating single drive bcachefs volume
pub fn bcachefs_format(
dev: &BlkDev,
compression: Option<String>,
password: Option<String>,
) -> Result<(), String> {
// sudo bcachefs format --compression=lz4 --background_compression=lz4 --encrypted /dev/loop0
// --data_checksum=none - do not make sense on single dev volumes
// sudo bcachefs format --force --compression=lz4 --background_compression=lz4 --encrypted --passphrase_file=./test.pass /dev/loop0
use std::fs;
use std::process::Command;
let mut arg = vec!["format", "--force", "--data_checksum=none"];
// if compression algorythm specified
if let Some(compresss_alg) = &compression {
arg.push(compresss_alg.as_str());
}
// if we want encrypted volume
if let Some(passw) = password {
// creating tmp file with password
fs::write("/tmp/bzzpsspass.txt", &passw).map_err(|ex| ex.to_string())?;
arg.push("--encrypted");
arg.push("--passphrase_file=/tmp/bzzpsspass.txt");
}
// add dev name at the end
let dev_name = dev.full_name();
arg.push(dev_name.as_str());
let out = Command::new("bcachefs")
.args(arg)
.output()
.map_err(|ex| ex.to_string())?;
// ignore any errors while deleting pass tmp file
let _ = fs::remove_file("/tmp/bzzpsspass.txt");
if out.status.success() {
Ok(())
} else {
Err(String::from_utf8(out.stderr).map_err(|ex| ex.to_string())?)
}
}
/// unlok encrypted bcache volume
pub fn bcachefs_unlock(dev: &BlkDev, pass: String) -> Result<(), String> {
use std::fs;
use std::process::Command;
// bcachefs unlock --file=/tmp/bzzpsspass.txt /dev/loop0
let dev_name = dev.full_name();
let arg = vec!["unlock", "--file=/tmp/bzzpsspass.txt ", dev_name.as_str()];
// creating tmp file with password
fs::write("/tmp/bzzpsspass.txt", &pass).map_err(|ex| ex.to_string())?;
let out = Command::new("bcachefs")
.args(arg)
.output()
.map_err(|ex| ex.to_string())?;
// ignore any errors while deleting pass tmp file
let _ = fs::remove_file("/tmp/bzzpsspass.txt");
if out.status.success() {
Ok(())
} else {
Err(String::from_utf8(out.stderr).map_err(|ex| ex.to_string())?)
}
}
/// create subvolume
pub fn bcachefs_create_subvolume(vol_path: &str) -> Result<(), String> {
use std::process::Command;
// sudo bcachefs subvolume create /mnt/test/nyan
let out = Command::new("bcachefs")
.args(["subvolume", "create", vol_path])
.output()
.map_err(|ex| ex.to_string())?;
if out.status.success() {
Ok(())
} else {
Err(String::from_utf8(out.stderr).map_err(|ex| ex.to_string())?)
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
+311
View File
@@ -0,0 +1,311 @@
// <Kira Installer - universal Linux installer.>
// Copyright (C) <2026> <Kira Foundation>
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
/*
Functions for creating with disk layout
*/
use crate::kira_disk_layout::*;
use std::process::Command;
use std::fs;
#[derive(Debug)]
pub struct CommandFailed{
stderr: Vec<u8>,
cmd: String,
}
impl std::fmt::Display for CommandFailed {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "Command failed! Command: {}; Stderr: {}", self.cmd, String::from_utf8(self.stderr.clone()).unwrap_or_else(|_|{"STDEER IS NOT VALID UTF-8".to_string()}))
}
}
impl CommandFailed {
pub fn new(cmd: &str, args: &Vec<&str>, stderr: Vec<u8>) -> Self {
Self {
stderr: stderr,
cmd: format!("{} {}", cmd, args.join(" ")),
}
}
}
#[derive(Debug)]
pub enum ExecCommandError {
IoError(std::io::Error),
FromUtf8Error(std::string::FromUtf8Error),
CommandFailed(CommandFailed),
Other(String),
}
// 2. Implement From for each wrapped error type
impl From<std::io::Error> for ExecCommandError {
fn from(err: std::io::Error) -> Self {
ExecCommandError::IoError(err)
}
}
impl From<std::string::FromUtf8Error> for ExecCommandError {
fn from(err: std::string::FromUtf8Error) -> Self {
ExecCommandError::FromUtf8Error(err)
}
}
impl From<CommandFailed> for ExecCommandError {
fn from(err: CommandFailed) -> Self {
ExecCommandError::CommandFailed(err)
}
}
impl From<String> for ExecCommandError {
fn from(err: String) -> Self {
ExecCommandError::Other(err)
}
}
impl std::fmt::Display for ExecCommandError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
ExecCommandError::IoError(e) => write!(f, "IO Error: {}", e),
ExecCommandError::FromUtf8Error(e) => {
write!(f, "IO streem to String parse Error: {}", e)
}
ExecCommandError::CommandFailed(ex) => {
write!(f, "{}", ex)
}
ExecCommandError::Other(msg) => write!(f, "Error: {}", msg),
}
}
}
// Implement std::error::Error
impl std::error::Error for ExecCommandError {}
/// exec given sommand with arguments, capturing stderr in case or failure
fn exec_command(cmd: &str, args: &Vec<&str>) -> Result<(), ExecCommandError> {
let out = Command::new(cmd).args(args).output()?;
if out.status.success() {
Ok(())
} else {
Err(CommandFailed::new(cmd, args, out.stderr).into())
}
}
/// exec given sommand with arguments, returning stdout parsed to UTF-8 string
/// capturing stderr in case or failure
fn exec_command_out(cmd: &str, args: &Vec<&str>) -> Result<String, ExecCommandError> {
let out = Command::new(cmd).args(args).output()?;
if out.status.success() {
Ok(String::from_utf8(out.stdout)?)
} else {
Err(CommandFailed::new(cmd, args, out.stderr).into())
}
}
/// sync system time with chrony
/// dinitctl start chrony
pub fn dinit_sync_time_chrony() -> Result<(), ExecCommandError> {
exec_command("dinitctl", &vec!["start", "chrony"])
}
/// Install base system
/// basestrap /mnt base base-devel dinit elogind-dinit
pub fn basestrap_dinit(root_dir: &str) -> Result<(), ExecCommandError> {
exec_command("basestrap", &vec![root_dir, "base", "base-devel", "dinit", "elogind-dinit"])
}
/// Executes parted command with given arguments
fn exec_parted(args: &Vec<&str>) -> Result<String, ExecCommandError> {
exec_command_out("parted", args)
}
fn parted_get_last_part_num(dev: &BlkDev) -> Result<u32, ExecCommandError> {
// parted -m /dev/loop0 print
let res = exec_parted(&vec!["-m", dev.full_name().as_str(), "print"])?;
match res.lines().last().and_then(|last_line| {
last_line
.split_once(':')
.and_then(|(first_part, _)| u32::from_str_radix(first_part, 10).ok())
}) {
Some(n) => Ok(n),
None => Err("Error parsing parted output".to_string().into()),
}
}
/// init gpt partition table
/// parted --script $install_device mklabel gpt
/// Its blocking function
pub fn parted_init_gpt_part_table(dev: &BlkDev) -> Result<(), ExecCommandError> {
let dev_full_name = dev.full_name();
let args = vec![
"--script",
&dev_full_name,
"mklabel",
"gpt",
];
exec_command("parted", &args)
}
const LINUX_ROOT_X86_64_TYPE: &str = "4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709";
/// creating partition from PartInfo specification
/// It assumes that we add partitions sequentially to empty space (for part attributes settings)
/// Otherwise can produce bonkers layout
pub fn parted_mkpart(dev: &BlkDev, part: &PartInfo) -> Result<(), ExecCommandError> {
let part_end = part.start + part.size;
// gpt label should be in double qutes
let gpt_label = if let Some(s) = &part.gpt_label {
format!("\"{}\"", s)
} else {
"\"\"".to_string()
};
// creating partition
exec_parted(&vec![
"--script",
dev.full_name().as_str(),
"mkpart",
gpt_label.as_str(),
part.fs_type.to_parted_str(),
part.start.to_parted_bytes_str().as_str(),
part_end.to_parted_bytes_str().as_str(),
])?;
// set partition options depending on its role
if let Some(role) = &part.role {
// getting part number of last created partition (hopefully)
let part_id = parted_get_last_part_num(dev)?;
match role {
PartRole::EFI => {
exec_parted(&vec![
"--script",
dev.full_name().as_str(),
"set",
&part_id.to_string(),
"esp",
"on",
])?;
}
// parted --script $install_device type 3 4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709
PartRole::ROOT => {
exec_parted(&vec![
"--script",
dev.full_name().as_str(),
"type",
&part_id.to_string(),
LINUX_ROOT_X86_64_TYPE,
])?;
}
_ => (),
}
};
Ok(())
}
/// creating single drive bcachefs volume
/// compression: lz4, zstd
pub fn bcachefs_format(
dev_name: &str,
compression: Option<String>,
password: Option<String>,
) -> Result<(), ExecCommandError> {
// sudo bcachefs format --compression=lz4 --background_compression=lz4 --encrypted /dev/loop0
// --data_checksum=none - do not make sense on single dev volumes
// sudo bcachefs format --force --compression=lz4 --background_compression=lz4 --encrypted --passphrase_file=./test.pass /dev/loop0
let mut arg = vec!["format", "--force"];
// if compression algorythm specified
let maybe_comp_cmd = compression.and_then(|alg| Some(format!("--compression={}", alg)));
if let Some(comp_cmd) = &maybe_comp_cmd {
arg.push(comp_cmd);
}
// if we want encrypted volume
if let Some(passw) = password {
// creating tmp file with password
fs::write("/tmp/bzzpsspass.txt", &passw)?;
arg.push("--encrypted");
arg.push("--passphrase_file=/tmp/bzzpsspass.txt");
}
// add dev name at the end
arg.push(dev_name);
let out = exec_command("bcachefs", &arg);
// ignore any errors while deleting pass tmp file
let _ = fs::remove_file("/tmp/bzzpsspass.txt");
out
}
/// unlok encrypted bcache volume
pub fn bcachefs_unlock(dev_name: &str, pass: &str) -> Result<(), ExecCommandError> {
// bcachefs unlock --file=/tmp/bzzpsspass.txt /dev/loop0
let arg = vec!["unlock", "--file=/tmp/bzzpsspass.txt ", dev_name];
// creating tmp file with password
fs::write("/tmp/bzzpsspass.txt", &pass)?;
let out = exec_command("bcachefs", &arg);
// ignore any errors while deleting pass tmp file
let _ = fs::remove_file("/tmp/bzzpsspass.txt");
out
}
/// create subvolume
pub fn bcachefs_create_subvolume(vol_path: &str) -> Result<(), ExecCommandError> {
// sudo bcachefs subvolume create /mnt/test/nyan
exec_command("bcachefs", &vec!["subvolume", "create", vol_path])
}
/// mount bcachefs
pub fn bcachefs_mount(dev_name: &str, mount_point: &str) -> Result<(), ExecCommandError> {
// sudo mount -t bcachefs /dev/loop0 /mnt/test
exec_command("mount", &vec!["-t", "bcachefs", dev_name, mount_point])
}
pub fn fatlabel(dev: &str, label: &str) -> Result<(), ExecCommandError> {
//fatlabel /dev/sda1 ESP
exec_command("fatlabel", &vec![dev, label])
}
pub fn mkfs_fat32(dev: &str, maybe_label: Option<&str>) -> Result<(), ExecCommandError> {
//mkfs.fat -F 32 /dev/sda1
exec_command("mkfs.fat", &vec!["-F", "32", dev])?;
// if need to set label
if let Some(label) = maybe_label {
fatlabel(dev, label)
} else {
Ok(())
}
}
/// mkfs.fat -F 32 /dev/sda1
/// fatlabel /dev/sda1 ESP
pub fn mkfs_esp(dev: &str) -> Result<(), ExecCommandError> {
mkfs_fat32(dev, Some("ESP"))
}
pub fn mkswap(dev: &str) -> Result<(), ExecCommandError> {
//mkswap -L SWAP /dev/sda4
exec_command("mkswap", &vec!["L", "SWAP", dev])
}
+15
View File
@@ -20,6 +20,7 @@
*/ */
use iced::{Color, Theme, color}; use iced::{Color, Theme, color};
use iced::widget::container;
// Function returns theme to be used by installer // Function returns theme to be used by installer
pub fn main_theme() -> Theme { pub fn main_theme() -> Theme {
@@ -38,6 +39,20 @@ pub fn change_lightnes(c: &Color, factor: f32) -> Color {
res res
} }
pub fn dialog_background(_theme: &Theme) -> container::Style {
let mut back = _theme.palette().background.clone();
back.a = 0.8;
container::Style {
background: Some(iced::Background::Color(back)),
..container::Style::default()
}
}
pub fn warning_dialog(_theme: &Theme) -> container::Style {
container::bordered_box(_theme).background(color!(0xDB5375))
}
// pub fn text_with_border(_theme: &Theme) -> container::Style { // pub fn text_with_border(_theme: &Theme) -> container::Style {
// container::Style { // container::Style {
+1 -1
View File
@@ -52,5 +52,5 @@
"security.pass_middle": "normal security", "security.pass_middle": "normal security",
"security.pass_hight": "hight security", "security.pass_hight": "hight security",
"install.caption": "Now we will beee install Bzz Linux to your PC", "install.caption": "Now we will beee install Bzz Linux to your PC",
"install.warning": "We a ready to start installation, this action will destroy all data on select drive!\nDo you want to proceed?" "install.warning": "We a ready to start installation, this action will destroy all data on select drive!\n\nDo you want to proceed?"
} }
+84 -57
View File
@@ -35,6 +35,7 @@ use crate::stages::welcome::WelcomeStage;
rust_i18n::i18n!("src/locales", fallback = "en"); rust_i18n::i18n!("src/locales", fallback = "en");
mod kira_color_bar; mod kira_color_bar;
mod kira_disk_layout; mod kira_disk_layout;
mod kira_system;
mod kira_logger; mod kira_logger;
mod kira_scroll_list; mod kira_scroll_list;
mod kira_size; mod kira_size;
@@ -53,6 +54,7 @@ enum Views {
Keyboard(stages::keyboard::KeyboardStage), Keyboard(stages::keyboard::KeyboardStage),
Partition(stages::partition::PartitionStage), Partition(stages::partition::PartitionStage),
Security(stages::security::SecurityStage), Security(stages::security::SecurityStage),
Install(stages::install::InstallStage),
} }
enum Message { enum Message {
@@ -65,39 +67,36 @@ enum Message {
Keyboard(stages::keyboard::Message), Keyboard(stages::keyboard::Message),
Partition(stages::partition::Message), Partition(stages::partition::Message),
Security(stages::security::Message), Security(stages::security::Message),
Install(stages::install::Message),
} }
struct KiraState { struct KiraState {
current_view: Views, current_view: Views,
toml_config: toml::Table, k_config: KiraConfig,
config: KiraConfig,
stages_save: Vec<Views>, stages_save: Vec<Views>,
} }
const CONFIG_PATH_STR: &str = "kira_config.toml"; // const CONFIG_PATH_STR: &str = "kira_config.toml";
fn load_kira_config(config_path: &str) -> Result<toml::Table, Box<dyn std::error::Error>> { // fn load_kira_config(config_path: &str) -> Result<toml::Table, Box<dyn std::error::Error>> {
use std::fs; // use std::fs;
use toml::Table; // use toml::Table;
// 1. Read the file content into a String // // 1. Read the file content into a String
let content = fs::read_to_string(config_path)?; // let content = fs::read_to_string(config_path)?;
// 2. Parse the string into a Table // // 2. Parse the string into a Table
let table: Table = content.parse()?; // let table: Table = content.parse()?;
log::info!("{:?}", table); // log::info!("{:?}", table);
Ok(table) // Ok(table)
} // }
impl KiraState { impl KiraState {
fn boot() -> (Self, Task<Message>) { fn boot() -> (Self, Task<Message>) {
( (
Self { Self {
current_view: Views::Start, current_view: Views::Start,
toml_config: toml::Table::new(), k_config: KiraConfig ::default(),
config: KiraConfig {
config_trail: Vec::new(),
},
stages_save: Vec::new(), stages_save: Vec::new(),
}, },
Task::done(Message::Start), Task::done(Message::Start),
@@ -115,30 +114,27 @@ fn view(k_state: &KiraState) -> Element<'_, Message> {
Views::Locale(locale_stage) => locale_stage.view().map(Message::Locale), Views::Locale(locale_stage) => locale_stage.view().map(Message::Locale),
Views::Keyboard(keyboard_stage) => keyboard_stage.view().map(Message::Keyboard), Views::Keyboard(keyboard_stage) => keyboard_stage.view().map(Message::Keyboard),
Views::Partition(partition_stage) => partition_stage.view().map(Message::Partition), Views::Partition(partition_stage) => partition_stage.view().map(Message::Partition),
Views::Security(security_stage) => security_stage.view().map(Message::Security) Views::Security(security_stage) => security_stage.view().map(Message::Security),
Views::Install(install_stage) => install_stage.view().map(Message::Install),
} }
} }
fn update(k_state: &mut KiraState, message: Message) -> Task<Message> { fn update(k_state: &mut KiraState, message: Message) -> Task<Message> {
match message { match message {
Message::Start => match load_kira_config(CONFIG_PATH_STR) { Message::Start => {
Ok(conf) => { log::info!("Starting!");
log::info!("Config loaded!"); k_state.current_view = Views::Welcome(WelcomeStage::new(k_state.k_config.clone()));
k_state.toml_config = conf;
k_state.current_view = Views::Welcome(WelcomeStage::new());
Task::none() Task::none()
}
Err(ex) => {
log::error!("Error reading config {}: {}", CONFIG_PATH_STR, ex);
iced::exit()
}
}, },
Message::Welcome(wlc_msg) => { Message::Welcome(wlc_msg) => {
if let Views::Welcome(wlc_view) = &mut k_state.current_view { if let Views::Welcome(wlc_view) = &mut k_state.current_view {
match wlc_view.update(wlc_msg) { match wlc_view.update(wlc_msg) {
StageAction::Next(welcome_res) => { StageAction::Next(welcome_res) => {
k_state.config.config_trail.push(welcome_res); k_state.k_config = welcome_res;
let s_state = std::mem::replace(&mut k_state.current_view, Views::License(license::LicenseStage {})); let s_state = std::mem::replace(
&mut k_state.current_view,
Views::License(license::LicenseStage::new(k_state.k_config.clone())),
);
k_state.stages_save.push(s_state); k_state.stages_save.push(s_state);
Task::none() Task::none()
} }
@@ -154,15 +150,17 @@ fn update(k_state: &mut KiraState, message: Message) -> Task<Message> {
let action = license_view.update(license_message); let action = license_view.update(license_message);
match action { match action {
StageAction::Next(license_res) => { StageAction::Next(license_res) => {
k_state.config.config_trail.push(license_res); k_state.k_config = license_res;
let s_state = std::mem::replace(&mut k_state.current_view, Views::Network(network::NetworkStage::new(&k_state.toml_config))); let s_state = std::mem::replace(
&mut k_state.current_view,
Views::Network(network::NetworkStage::new(k_state.k_config.clone())),
);
k_state.stages_save.push(s_state); k_state.stages_save.push(s_state);
Task::done(Message::Network(network::Message::CheckNetwork)) Task::done(Message::Network(network::Message::CheckNetwork))
} }
StageAction::Abort => iced::exit(), StageAction::Abort => iced::exit(),
StageAction::Back => { StageAction::Back => {
k_state.current_view = k_state.stages_save.pop().unwrap(); k_state.current_view = k_state.stages_save.pop().unwrap();
k_state.config.config_trail.pop();
Task::none() Task::none()
} }
StageAction::None => Task::none(), StageAction::None => Task::none(),
@@ -178,14 +176,16 @@ fn update(k_state: &mut KiraState, message: Message) -> Task<Message> {
network::UpdateResult::Task(t) => t.map(Message::Network), network::UpdateResult::Task(t) => t.map(Message::Network),
network::UpdateResult::StageAction(action) => match action { network::UpdateResult::StageAction(action) => match action {
StageAction::Next(network_res) => { StageAction::Next(network_res) => {
k_state.config.config_trail.push(network_res); k_state.k_config = network_res;
let s_state = std::mem::replace(&mut k_state.current_view,Views::TimeZone(stages::timezone::TimeZoneStage::new())); let s_state = std::mem::replace(
&mut k_state.current_view,
Views::TimeZone(stages::timezone::TimeZoneStage::new(k_state.k_config.clone())),
);
k_state.stages_save.push(s_state); k_state.stages_save.push(s_state);
Task::none() Task::none()
} }
StageAction::Back => { StageAction::Back => {
k_state.current_view = k_state.stages_save.pop().unwrap(); k_state.current_view = k_state.stages_save.pop().unwrap();
k_state.config.config_trail.pop();
Task::none() Task::none()
} }
_ => Task::none(), _ => Task::none(),
@@ -200,14 +200,16 @@ fn update(k_state: &mut KiraState, message: Message) -> Task<Message> {
let action = timezone_view.update(timezone_message); let action = timezone_view.update(timezone_message);
match action { match action {
StageAction::Next(tz_res) => { StageAction::Next(tz_res) => {
k_state.config.config_trail.push(tz_res); k_state.k_config = tz_res;
let s_state = std::mem::replace(&mut k_state.current_view,Views::Locale(stages::locale::LocaleStage::new(&k_state.config))); let s_state = std::mem::replace(
&mut k_state.current_view,
Views::Locale(stages::locale::LocaleStage::new(k_state.k_config.clone())),
);
k_state.stages_save.push(s_state); k_state.stages_save.push(s_state);
Task::none() Task::none()
} }
StageAction::Abort => iced::exit(), StageAction::Abort => iced::exit(),
StageAction::Back => { StageAction::Back => {
k_state.config.config_trail.pop();
k_state.current_view = k_state.stages_save.pop().unwrap(); k_state.current_view = k_state.stages_save.pop().unwrap();
Task::none() Task::none()
} }
@@ -221,13 +223,15 @@ fn update(k_state: &mut KiraState, message: Message) -> Task<Message> {
if let Views::Locale(locale_view) = &mut k_state.current_view { if let Views::Locale(locale_view) = &mut k_state.current_view {
match locale_view.update(locale_msg) { match locale_view.update(locale_msg) {
StageAction::Next(locale_res) => { StageAction::Next(locale_res) => {
k_state.config.config_trail.push(locale_res); k_state.k_config = locale_res;
let s_state = std::mem::replace(&mut k_state.current_view,Views::Keyboard(stages::keyboard::KeyboardStage::new())); let s_state = std::mem::replace(
k_state.stages_save.push(s_state); &mut k_state.current_view,
Views::Keyboard(stages::keyboard::KeyboardStage::new(k_state.k_config.clone())),
);
k_state.stages_save.push(s_state);
Task::none() Task::none()
} }
StageAction::Back => { StageAction::Back => {
k_state.config.config_trail.pop();
k_state.current_view = k_state.stages_save.pop().unwrap(); k_state.current_view = k_state.stages_save.pop().unwrap();
Task::none() Task::none()
} }
@@ -241,10 +245,13 @@ fn update(k_state: &mut KiraState, message: Message) -> Task<Message> {
if let Views::Keyboard(keyboard_view) = &mut k_state.current_view { if let Views::Keyboard(keyboard_view) = &mut k_state.current_view {
match keyboard_view.update(keyboard_msg) { match keyboard_view.update(keyboard_msg) {
StageAction::Next(keyboard_res) => { StageAction::Next(keyboard_res) => {
match stages::partition::PartitionStage::new(&k_state.toml_config) { match stages::partition::PartitionStage::new(k_state.k_config.clone()) {
Ok(part_stage) => { Ok(part_stage) => {
k_state.config.config_trail.push(keyboard_res); k_state.k_config = keyboard_res;
let s_state = std::mem::replace(&mut k_state.current_view,Views::Partition(part_stage)); let s_state = std::mem::replace(
&mut k_state.current_view,
Views::Partition(part_stage),
);
k_state.stages_save.push(s_state); k_state.stages_save.push(s_state);
} }
Err(ex) => { Err(ex) => {
@@ -254,7 +261,6 @@ fn update(k_state: &mut KiraState, message: Message) -> Task<Message> {
Task::none() Task::none()
} }
StageAction::Back => { StageAction::Back => {
k_state.config.config_trail.pop();
k_state.current_view = k_state.stages_save.pop().unwrap(); k_state.current_view = k_state.stages_save.pop().unwrap();
Task::none() Task::none()
} }
@@ -263,18 +269,20 @@ fn update(k_state: &mut KiraState, message: Message) -> Task<Message> {
} else { } else {
Task::none() Task::none()
} }
}, }
Message::Partition(partition_msg) => { Message::Partition(partition_msg) => {
if let Views::Partition(partition_view) = &mut k_state.current_view { if let Views::Partition(partition_view) = &mut k_state.current_view {
match partition_view.update(partition_msg) { match partition_view.update(partition_msg) {
StageAction::Next(partition_res) => { StageAction::Next(partition_res) => {
k_state.config.config_trail.push(partition_res); k_state.k_config = partition_res;
let s_state = std::mem::replace(&mut k_state.current_view,Views::Security(stages::security::SecurityStage::new())); let s_state = std::mem::replace(
&mut k_state.current_view,
Views::Security(stages::security::SecurityStage::new(k_state.k_config.clone())),
);
k_state.stages_save.push(s_state); k_state.stages_save.push(s_state);
Task::none() Task::none()
} }
StageAction::Back => { StageAction::Back => {
k_state.config.config_trail.pop();
k_state.current_view = k_state.stages_save.pop().unwrap(); k_state.current_view = k_state.stages_save.pop().unwrap();
Task::none() Task::none()
} }
@@ -283,17 +291,20 @@ fn update(k_state: &mut KiraState, message: Message) -> Task<Message> {
} else { } else {
Task::none() Task::none()
} }
}, }
Message::Security(security_msg) => { Message::Security(security_msg) => {
if let Views::Security(security_view) = &mut k_state.current_view { if let Views::Security(security_view) = &mut k_state.current_view {
match security_view.update(security_msg) { match security_view.update(security_msg) {
StageAction::Next(security_res) => { StageAction::Next(security_res) => {
k_state.config.config_trail.push(security_res); k_state.k_config = security_res;
//let s_state = std::mem::replace(&mut k_state.current_view, let s_state = std::mem::replace(
&mut k_state.current_view,
Views::Install(stages::install::InstallStage::new(k_state.k_config.clone())),
);
k_state.stages_save.push(s_state);
Task::none() Task::none()
} }
StageAction::Back => { StageAction::Back => {
k_state.config.config_trail.pop();
k_state.current_view = k_state.stages_save.pop().unwrap(); k_state.current_view = k_state.stages_save.pop().unwrap();
Task::none() Task::none()
} }
@@ -302,8 +313,24 @@ fn update(k_state: &mut KiraState, message: Message) -> Task<Message> {
} else { } else {
Task::none() Task::none()
} }
}, }
Message::Install(install_msg) => {
if let Views::Install(install_view) = &mut k_state.current_view {
let update_result = install_view.update(install_msg);
match update_result {
stages::install::Update::Task(t) => t.map(Message::Install),
stages::install::Update::StgAct(stage_action) => match stage_action {
StageAction::Back => {
k_state.current_view = k_state.stages_save.pop().unwrap();
Task::none()
}
_ => Task::none(),
},
}
} else {
Task::none()
}
}
} }
} }
+59 -52
View File
@@ -18,47 +18,38 @@
This file contains basic enums and structs to be used with stages. This file contains basic enums and structs to be used with stages.
*/ */
use iced::wgpu::naga::compact::KeepUnused::No;
use crate::stages; use crate::stages;
// #[derive(Debug, Clone)] // #[derive(Debug, Clone)]
// pub enum ConfigValue { // pub enum StageResult {
// String(String), // WelcomeStageResult(stages::welcome::WelcomeStageResult),
// I64(i64), // NetworkStageResult(stages::network::NetworkStageResult),
// U64(u64), // LocaleStageResult(stages::locale::LocaleStageResult),
// F64(f64), // TimeZoneStageResult(stages::timezone::TimeZoneStageResult),
// Bool(bool), // KeyboardStageResult(stages::keyboard::KeyboardStageResult),
// PartLayout(PartLayout), // SecurityStageResult(stages::security::SecurityStageResult),
// KiraSize(KiraSize), // PartitionStageResult(stages::partition::PartitionStageResult),
// Vector(Vec<ConfigValue>), // None,
// Dictionary(HashMap<String, ConfigValue>),
// } // }
#[derive(Debug, Clone)] // impl StageResult {
pub enum StageResult { // pub fn name(&self) -> String {
WelcomeStageResult(stages::welcome::WelcomeStageResult), // match self {
NetworkStageResult(stages::network::NetworkStageResult), // Self::LocaleStageResult(_) => "locale".into(),
LocaleStageResult(stages::locale::LocaleStageResult), // Self::WelcomeStageResult(_) => "welcome".into(),
TimeZoneStageResult(stages::timezone::TimeZoneStageResult), // Self::NetworkStageResult(_) => "network".into(),
KeyboardStageResult(stages::keyboard::KeyboardStageResult), // Self::TimeZoneStageResult(_) => "timezone".into(),
SecurityStageResult(stages::security::SecurityStageResult), // Self::KeyboardStageResult(_) => "keyboard".into(),
PartitionStageResult(stages::partition::PartitionStageResult), // Self::PartitionStageResult(_) => "partition".into(),
None, // Self::SecurityStageResult(_) => "security".into(),
} // Self::None => "none".into(),
// }
// }
// }
impl StageResult {
pub fn name(&self) -> String {
match self {
Self::LocaleStageResult(_) => "locale".into(),
Self::WelcomeStageResult(_) => "welcome".into(),
Self::NetworkStageResult(_) => "network".into(),
Self::TimeZoneStageResult(_) => "timezone".into(),
Self::KeyboardStageResult(_) => "keyboard".into(),
Self::PartitionStageResult(_) => "partition".into(),
Self::SecurityStageResult(_) => "security".into(),
Self::None => "none".into(),
}
}
}
// impl StageResult { // impl StageResult {
// pub fn new(name: &str) -> Self { // pub fn new(name: &str) -> Self {
// Self { // Self {
@@ -129,36 +120,52 @@ impl StageResult {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct KiraConfig { pub struct KiraConfig {
pub config_trail: Vec<StageResult>, pub res_welcome: Option<stages::welcome::WelcomeStageResult>,
pub res_license: bool,
pub res_network: Option<stages::network::NetworkStageResult>,
pub res_timezone: Option<stages::timezone::TimeZoneStageResult>,
pub res_locale: Option<stages::locale::LocaleStageResult>,
pub res_keyboard: Option<stages::keyboard::KeyboardStageResult>,
pub res_partition: Option<stages::partition::PartitionStageResult>,
pub res_security: Option<stages::security::SecurityStageResult>,
pub res_install: bool,
} }
impl Default for KiraConfig { impl Default for KiraConfig {
fn default() -> Self { fn default() -> Self {
Self { Self {
config_trail: Vec::new(), res_welcome: None,
res_license: false,
res_network: None,
res_timezone: None,
res_locale: None,
res_keyboard: None,
res_partition: None,
res_security: None,
res_install: false,
} }
} }
} }
impl KiraConfig { // impl KiraConfig {
pub fn get_stage(&self, name: &str) -> Option<StageResult> { // pub fn get_stage(&self, name: &str) -> Option<StageResult> {
self.config_trail // self.config_trail
.iter() // .iter()
.find(|v| v.name() == name) // .find(|v| v.name() == name)
.and_then(|v| Some(v.clone())) // .and_then(|v| Some(v.clone()))
} // }
pub fn pop_last(&mut self) -> Option<StageResult> { // pub fn pop_last(&mut self) -> Option<StageResult> {
self.config_trail.pop() // self.config_trail.pop()
} // }
pub fn push(&mut self, stage_result: StageResult) { // pub fn push(&mut self, stage_result: StageResult) {
self.config_trail.push(stage_result); // self.config_trail.push(stage_result);
} // }
} // }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum StageAction { pub enum StageAction {
Back, Back,
None, None,
Next(StageResult), Next(KiraConfig),
Abort, Abort,
} }
+259 -71
View File
@@ -18,27 +18,119 @@
Actual installation script. Actual installation script.
*/ */
/// use crate::{
/// So. I am goind to make dir structure lile this kira_disk_layout::{self, BlkDev, FSType, PartLayout, PartRole},
/// /bzz/root kira_size::KiraSize,
/// /bzz/home kira_system::{self, ExecCommandError},
/// Mount root from it and binmount home kira_theming,
/// stage::{KiraConfig, StageAction},
stages::partition::PartitionStageResult,
};
use iced::{
Alignment, Task,
futures::{self, SinkExt, StreamExt, TryStreamExt, channel::mpsc::SendError},
widget,
};
use iced::{Color, Length, futures::channel::mpsc::Sender, widget::container};
use log; use log;
use crate::{
kira_disk_layout::{self, BlkDev, PartLayout}, kira_size::KiraSize, kira_theming, stage::{KiraConfig, StageAction, StageResult}
};
use iced::{Alignment, Task, futures::{self, SinkExt}, widget};
use rust_i18n::t; use rust_i18n::t;
use iced::futures::channel::mpsc::{Sender};
const EFI_BOOT_MOUNT_POINT: &str = "/beefi";
/// Creates new GPT table and partitions from PartLayout
pub fn create_partitions(part_layout: &PartLayout) -> Result<(), ExecCommandError> {
log::info!("Creating GPT part table...");
kira_system::parted_init_gpt_part_table(&part_layout.dev)?;
log::info!("Start to create partitions...");
for part in &part_layout.part_list {
log::info!("Creating partition: {}", part);
kira_system::parted_mkpart(&part_layout.dev, part)?;
}
Ok(())
}
/// inits bcachefs volume for installation to use
/// Formats device to bcachefs
/// Unlock it if encryption used
/// Mount to specified dir
/// creates subvolumes bzz/root bzz/home
pub fn bcachefs_init(
dev_name: &str,
mnt_dir: &str,
password: Option<String>,
comp_alg: Option<String>,
) -> Result<(), ExecCommandError> {
// format device
kira_system::bcachefs_format(dev_name, comp_alg, password.clone())?;
// if encryption used - unlock drive
if let Some(pass) = password {
kira_system::bcachefs_unlock(dev_name, pass.as_str())?;
}
//mount drive
kira_system::bcachefs_mount(dev_name, mnt_dir)?;
// Creating bzz-snaps directory for root snapshoots
std::fs::create_dir(format!("{}{}", mnt_dir, "/bzz-snaps"))?;
// Creating boot directory for efi mounting
std::fs::create_dir_all(format!("{}{}", mnt_dir, EFI_BOOT_MOUNT_POINT))?;
// create subvolumes
for vol_name in ["/home", "/usr", "/var", "/var/tmp"] {
let vol_path = format!("{}{}", mnt_dir, vol_name);
kira_system::bcachefs_create_subvolume(vol_path.as_str())?;
}
Ok(())
}
pub fn init_disk(part_layout: &PartLayout, mnt_dir: &str) -> Result<(), ExecCommandError> {
// use parted to create partition gpt layout
create_partitions(part_layout)?;
// format partitions
for part in &part_layout.part_list {
match part.role {
Some(PartRole::EFI) => {
if let Some(part_l) = part.partlabel_dev() {
kira_system::mkfs_esp(&part_l)?;
}
}
Some(PartRole::ROOT) => {
if let Some(part_l) = part.partlabel_dev() {
if let FSType::BCACHEFS(bc_par) = &part.fs_type {
bcachefs_init(
&part_l,
mnt_dir,
bc_par.password.clone(),
bc_par.comp_alg.clone(),
)?;
} else {
return Err(ExecCommandError::Other(
"ROOT partition is not BCACHEFS type!".into(),
));
}
}
}
Some(PartRole::SWAP) => {
if let Some(part_l) = part.partlabel_dev() {
kira_system::mkswap(&part_l)?;
}
}
_ => (),
}
}
Ok(())
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum InstallationState { enum InstallationState {
UserConfirmDialog, UserConfirmDialog,
Partitionning, Installing,
CopyFiles,
Configuring,
Finish, Finish,
Error, Error,
} }
@@ -48,19 +140,20 @@ pub struct InstallStage {
state: InstallationState, state: InstallationState,
progress: f32, progress: f32,
progress_message: String, progress_message: String,
kira_config: KiraConfig, part_config: PartitionStageResult,
modal_backgroud: Color,
k_config: KiraConfig,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Message { pub enum Message {
UserConfirms, UserConfirms,
UserDenies, UserDenies,
StartPartitioning, Sucess,
UpdateProgress(Result<(f32, String), String>),
PartitioningFinish(Result<(), String>),
Back,
Cancel, Cancel,
Finish, Finish,
UpdateProgress(Result<(f32, String), String>),
Failure(String),
} }
#[derive(Debug)] #[derive(Debug)]
@@ -69,47 +162,128 @@ pub enum Update {
Task(Task<Message>), Task(Task<Message>),
} }
async fn init_disk_async(part_layout: PartLayout, mnt_dir: String) -> Result<(), ExecCommandError> {
use blocking;
blocking::unblock(move || init_disk(&part_layout, &mnt_dir)).await
}
fn partition_disk(disk_layout: PartLayout, password: Option<String>) -> impl futures::Stream<Item = Result<(f32, String), String>> { fn partition_disk(
disk_layout: PartLayout,
password: Option<String>,
compression: Option<String>,
mnt_dir: String,
) -> impl futures::Stream<Item = Result<(f32, String), ExecCommandError>> {
use blocking; use blocking;
iced::stream::channel(100, |mut output: Sender<Result<(f32, String), String>>| async move { iced::stream::channel(
for i in 0..=1000 { 100,
|mut output: Sender<Result<(f32, String), ExecCommandError>>| async move {
//sleep(Duration::from_millis(10)).await; //sleep(Duration::from_millis(10)).await;
let dev = disk_layout.dev.clone(); let disk_layout_cloned = disk_layout.clone();
// creating gpt partition table // creating gpt partition table
match output.send(blocking::unblock(move || kira_disk_layout::parted_init_gpt_part_table(&dev)).await.and(Ok((1.0f32, String::new())))).await { let res = init_disk_async(disk_layout_cloned, mnt_dir).await;
Err(ex) =>{ output
.send(res.map(|_| (1.1f32, "Formatting bcachefs".into())))
.await
.unwrap();
if res.is_err() {
return;
}
let res = init_disk_async(disk_layout_cloned).await;
output
.send(res.map(|_| (1.1f32, "Formatting bcachefs".into())))
.await
.unwrap();
if res.is_err() {
return;
}
// creating partitions
let dev = disk_layout.dev.clone();
let part_list = disk_layout.part_list.clone();
match output
.send(
blocking::unblock(move || {
let mut res = Ok(());
for part in part_list {
match kira_system::parted_mkpart(&dev, &part) {
Ok(_) => (),
Err(ex) => {
res = Err(ex);
break;
}
}
}
res
})
.await
.and(Ok((5.0f32, "Creating partitions".into()))),
)
.await
{
Err(ex) => {
log::error!("Error creating GPT partition table: {}", ex.to_string()); log::error!("Error creating GPT partition table: {}", ex.to_string());
return; return;
}, }
_ => () _ => (),
};
// creating bcachefs filesystem
// /dev/disk/by-partlabel/
let compression_cloned = compression.clone();
let password_cloned = password.clone();
match output
.send(
blocking::unblock(move || {
bcachefs_init(
"/dev/disk/by-partlabel/bee-root",
compression_cloned,
password_cloned,
"/mnt/bzzpss-install",
)
})
.await
.and(Ok((10.0f32, "Creating partition table".into()))),
)
.await
{
Err(ex) => {
log::error!("Error creating GPT partition table: {}", ex.to_string());
return;
}
_ => (),
}; };
// Check if send fails (receiver dropped/cancelled) // Check if send fails (receiver dropped/cancelled)
// if output.send(res).await.is_err() { // if output.send(res).await.is_err() {
// return; // Exit early if UI is gone // return; // Exit early if UI is gone
// } // }
}
// Optional: Send completion or error state here
// Optional: Send completion or error state here // output.send(Message::WorkFailed).await.ok();
// output.send(Message::WorkFailed).await.ok(); },
}) )
} }
impl InstallStage { impl InstallStage {
pub fn new(config: &KiraConfig) -> Self { pub fn new(k_config: KiraConfig) -> Self {
let mut modal_backgroud = kira_theming::main_theme().palette().background;
modal_backgroud.a = 0.5;
Self { Self {
modal_backgroud: modal_backgroud,
state: InstallationState::UserConfirmDialog, state: InstallationState::UserConfirmDialog,
progress: 0.0, progress: 0.0,
progress_message: String::new(), progress_message: String::new(),
kira_config: config.clone(), part_config: k_config.res_partition.clone().expect("Partition stage result should be present in KiraConfig!"),
k_config: k_config,
} }
} }
fn gen_result(&self) -> StageResult { fn gen_result(&mut self) -> KiraConfig {
StageResult::None self.k_config.res_install = true;
self.k_config.clone()
} }
pub fn update(&mut self, message: Message) -> Update { pub fn update(&mut self, message: Message) -> Update {
@@ -117,23 +291,22 @@ impl InstallStage {
Message::UserDenies => Update::StgAct(StageAction::Back), Message::UserDenies => Update::StgAct(StageAction::Back),
Message::UserConfirms => { Message::UserConfirms => {
// starting installation process here // starting installation process here
let part_data = self.kira_config.config_trail.iter().find_map(|v| match v { log::info!("Starting disk partitioning.");
StageResult::PartitionStageResult(res) => Some(res.clone()),
_ => None, self.state = InstallationState::Installing;
}).unwrap(); let disk_layout = self.part_config.part_layout.clone();
self.state = InstallationState::Partitionning; let disk_password = self.part_config.password.clone();
let disk_layout = part_data.part_layout.clone(); let disk_compression = Some("lz4".to_string());
let disk_password = part_data.password.clone(); Update::Task(Task::run(
partition_disk(disk_layout, disk_password, disk_compression)
.map_err(|ex| ex.to_string()),
Update::Task(Task::run(partition_disk(disk_layout, disk_password), Message::UpdateProgress)) Message::UpdateProgress,
))
//Update::Task(Task::perform(, Message::PartitioningFinish)) //Update::Task(Task::perform(, Message::PartitioningFinish))
} }
Message::StartPartitioning => Update::StgAct(StageAction::None),
Message::PartitioningFinish(res) => Update::StgAct(StageAction::None),
Message::UpdateProgress(maybe_msg) => { Message::UpdateProgress(maybe_msg) => {
match maybe_msg { match maybe_msg {
Ok((progress, msg))=> { Ok((progress, msg)) => {
self.progress = progress; self.progress = progress;
self.progress_message = msg; self.progress_message = msg;
Update::StgAct(StageAction::None) Update::StgAct(StageAction::None)
@@ -145,10 +318,13 @@ impl InstallStage {
} }
} }
//Update::StgAct(StageAction::None) //Update::StgAct(StageAction::None)
}
}, Message::Failure(ex) => {
self.state = InstallationState::Error;
Update::StgAct(StageAction::Abort)
}
Message::Cancel => Update::StgAct(StageAction::Abort), Message::Cancel => Update::StgAct(StageAction::Abort),
Message::Back => Update::StgAct(StageAction::Back), Message::Sucess => Update::StgAct(StageAction::None),
Message::Finish => Update::StgAct(StageAction::None), Message::Finish => Update::StgAct(StageAction::None),
} }
} }
@@ -161,12 +337,12 @@ impl InstallStage {
}; };
// Embed the image bytes into the executable // Embed the image bytes into the executable
let welcom_logo_handle = widget::image::Handle::from_bytes(kira_theming::get_logo_bytes()); let logo_handle = widget::image::Handle::from_bytes(kira_theming::get_logo_bytes());
let main_content = widget::column![ let main_content = widget::column![
widget::container( widget::container(
widget::column![ widget::column![
widget::image(welcom_logo_handle) widget::image(logo_handle)
.width(iced::Pixels(128.0)) .width(iced::Pixels(128.0))
.height(iced::Pixels(128.0)), .height(iced::Pixels(128.0)),
widget::text(t!("install.caption")), widget::text(t!("install.caption")),
@@ -193,22 +369,34 @@ impl InstallStage {
if self.state == InstallationState::UserConfirmDialog { if self.state == InstallationState::UserConfirmDialog {
page_stack page_stack
.push( .push(widget::opaque(
widget::column![ container(
widget::text(t!("install.warning")), container(
widget::row![ widget::column![
widget::button(widget::text(t!("button.no"))) widget::text(t!("install.warning")).align_x(Alignment::Center),
.on_press(Message::UserDenies), widget::row![
widget::space::horizontal(), // Pushes the right button to the far right widget::button(widget::text(t!("button.no")))
widget::button(widget::text(t!("button.yes"))) .on_press(Message::UserDenies),
.on_press(Message::UserConfirms) widget::space::horizontal(), // Pushes the right button to the far right
] widget::button(widget::text(t!("button.yes")))
.width(iced::Length::Fill) .on_press(Message::UserConfirms)
.align_y(Alignment::End) ]
.padding(10) .padding(10)
] ]
.align_x(Alignment::Center), .spacing(10)
) .padding(10)
.width(512)
.align_x(Alignment::Center),
)
.style(kira_theming::warning_dialog),
)
.style(container::bordered_box)
.style(kira_theming::dialog_background)
.align_x(Alignment::Center)
.align_y(Alignment::Center)
.height(Length::Fill)
.width(Length::Fill),
))
.into() .into()
} else { } else {
page_stack.into() page_stack.into()
+9 -6
View File
@@ -19,7 +19,7 @@
*/ */
use crate::kira_scroll_list::{self, ListViewMessage}; use crate::kira_scroll_list::{self, ListViewMessage};
use crate::stage::{StageAction, StageResult}; use crate::stage::{KiraConfig, StageAction};
use iced::{Alignment, Length, widget}; use iced::{Alignment, Length, widget};
use log; use log;
use rust_i18n::t; use rust_i18n::t;
@@ -119,9 +119,9 @@ pub struct KeyboardStage {
variants_map: HashMap<String, Vec<Variant>>, variants_map: HashMap<String, Vec<Variant>>,
variants: Vec<Variant>, variants: Vec<Variant>,
variant: Option<usize>, variant: Option<usize>,
keyboard_layout: Option<KeyboarLayout>, keyboard_layout: Option<KeyboarLayout>,
// selected_kbd_layout_id: Option<usize>, // selected_kbd_layout_id: Option<usize>,
k_config: KiraConfig,
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
@@ -230,7 +230,7 @@ fn get_layouts_blocking() -> std::io::Result<(
} }
impl KeyboardStage { impl KeyboardStage {
pub fn new() -> Self { pub fn new(k_config: KiraConfig) -> Self {
match get_layouts_blocking() { match get_layouts_blocking() {
Ok((models, layouts, variants_map)) => { Ok((models, layouts, variants_map)) => {
let def_layout = layouts let def_layout = layouts
@@ -258,6 +258,7 @@ impl KeyboardStage {
layout: def_layout, layout: def_layout,
variant: Some(0), variant: Some(0),
keyboard_layout: keyboard_layout, keyboard_layout: keyboard_layout,
k_config: k_config,
} }
} }
Err(ex) => { Err(ex) => {
@@ -274,19 +275,21 @@ impl KeyboardStage {
layout: None, layout: None,
variant: None, variant: None,
keyboard_layout: None, keyboard_layout: None,
k_config: k_config,
} }
} }
} }
} }
fn gen_result(&self) -> StageResult { fn gen_result(&mut self) -> KiraConfig {
StageResult::KeyboardStageResult(KeyboardStageResult { self.k_config.res_keyboard = Some(KeyboardStageResult {
keyboard_model: self.model.clone().expect("Keyboard model must be choosed!"), keyboard_model: self.model.clone().expect("Keyboard model must be choosed!"),
keyboard_layout: self keyboard_layout: self
.keyboard_layout .keyboard_layout
.clone() .clone()
.expect("Keyboard layout must be choosed!"), .expect("Keyboard layout must be choosed!"),
}) });
self.k_config.clone()
} }
pub fn update(&mut self, message: Message) -> StageAction { pub fn update(&mut self, message: Message) -> StageAction {
+12 -5
View File
@@ -23,10 +23,12 @@ use iced::{Alignment, widget};
use rust_i18n::t; use rust_i18n::t;
use crate::stage; use crate::stage;
use crate::stage::StageResult; use crate::stage::KiraConfig;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct LicenseStage {} pub struct LicenseStage {
k_config: KiraConfig,
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Message { pub enum Message {
@@ -42,13 +44,18 @@ pub enum Message {
//const LICENSE_TEXT: &str = include_str!("gpl-3.0.txt"); //const LICENSE_TEXT: &str = include_str!("gpl-3.0.txt");
impl LicenseStage { impl LicenseStage {
fn accepted() -> StageResult { pub fn new(k_config: KiraConfig) -> Self {
StageResult::None Self { k_config: k_config }
}
fn accepted(&mut self) -> KiraConfig {
self.k_config.res_license = true;
self.k_config.clone()
} }
pub fn update(&mut self, message: Message) -> stage::StageAction { pub fn update(&mut self, message: Message) -> stage::StageAction {
match message { match message {
Message::Accept => stage::StageAction::Next(Self::accepted()), Message::Accept => stage::StageAction::Next(self.accepted()),
Message::Back => stage::StageAction::Back, Message::Back => stage::StageAction::Back,
Message::Decline => stage::StageAction::Abort, Message::Decline => stage::StageAction::Abort,
} }
+14 -11
View File
@@ -20,7 +20,7 @@
use crate::{ use crate::{
kira_theming, kira_theming,
stage::{KiraConfig, StageAction, StageResult}, stage::{KiraConfig, StageAction},
}; };
use iced::{Alignment, widget}; use iced::{Alignment, widget};
use rust_i18n::t; use rust_i18n::t;
@@ -136,6 +136,7 @@ pub struct LocaleStage {
locales: Vec<LocaleData>, locales: Vec<LocaleData>,
lang_locale_text: String, lang_locale_text: String,
all_locale_text: String, all_locale_text: String,
k_config: KiraConfig,
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
@@ -153,12 +154,12 @@ pub enum Message {
} }
impl LocaleStage { impl LocaleStage {
pub fn new(kira_config: &KiraConfig) -> Self { pub fn new(k_config: KiraConfig) -> Self {
// get seelctet language code from welcome stage // get seelctet language code from welcome stage
let maybe_lang = kira_config.config_trail.iter().find_map(|v| match v { let maybe_lang = k_config
StageResult::WelcomeStageResult(res) => Some(res.loc_code.clone()), .res_welcome
_ => None, .as_ref()
}); .and_then(|rw| Some(rw.loc_code.clone()));
let raw_loc_codes = get_locales_codes_list_blocking().unwrap(); let raw_loc_codes = get_locales_codes_list_blocking().unwrap();
let raw_loc_descr = get_locales_description_blocking().unwrap(); let raw_loc_descr = get_locales_description_blocking().unwrap();
@@ -210,24 +211,26 @@ impl LocaleStage {
locales: locales, locales: locales,
lang_locale_text: lang_locale_text, lang_locale_text: lang_locale_text,
all_locale_text: all_locale_text, all_locale_text: all_locale_text,
k_config: k_config,
} }
} }
fn gen_result(&self) -> StageResult { fn gen_result(&mut self) -> KiraConfig {
if let Some(lang_locale) = &self.lang_locale self.k_config.res_locale = if let Some(lang_locale) = &self.lang_locale
&& let Some(formats_locale) = &self.formats_locale && let Some(formats_locale) = &self.formats_locale
{ {
StageResult::LocaleStageResult(LocaleStageResult { Some(LocaleStageResult {
lang_locale: lang_locale.clone(), lang_locale: lang_locale.clone(),
formats_locale: formats_locale.clone(), formats_locale: formats_locale.clone(),
}) })
} else { } else {
let loc = LocaleData::default(); let loc = LocaleData::default();
StageResult::LocaleStageResult(LocaleStageResult { Some(LocaleStageResult {
lang_locale: loc.clone(), lang_locale: loc.clone(),
formats_locale: loc, formats_locale: loc,
}) })
} };
self.k_config.clone()
} }
pub fn update(&mut self, message: Message) -> StageAction { pub fn update(&mut self, message: Message) -> StageAction {
+18 -30
View File
@@ -23,10 +23,10 @@ use iced::{Alignment, Task, widget};
use iced_moving_picture::widget::apng; use iced_moving_picture::widget::apng;
use log; use log;
use rust_i18n::t; use rust_i18n::t;
use toml::Table;
use crate::stage; use crate::stage::{self, KiraConfig};
use crate::stage::StageResult;
const REQIRE_NETWORK: bool = false;
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub enum State { pub enum State {
@@ -41,21 +41,21 @@ pub enum CheckResult {
CheckError, CheckError,
} }
#[derive(Debug, Clone, PartialEq)]
pub struct NetworkStageResult {
pub internet_active: bool,
pub use_net_settings: bool,
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct NetworkStage { pub struct NetworkStage {
internet_active: bool, internet_active: bool,
state: State, state: State,
use_net_settings: bool, use_net_settings: bool,
reqire_network: bool,
spinner_frames: apng::Frames, spinner_frames: apng::Frames,
logo_handle: widget::image::Handle, logo_handle: widget::image::Handle,
status_message: String, status_message: String,
} k_config: KiraConfig,
#[derive(Debug, Clone, PartialEq)]
pub struct NetworkStageResult {
pub internet_active: bool,
pub use_net_settings: bool,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@@ -100,21 +100,7 @@ async fn check_connected() -> CheckResult {
} }
impl NetworkStage { impl NetworkStage {
pub fn new(toml_config: &Table) -> Self { pub fn new(k_config: KiraConfig) -> Self {
let mut reqire_network = false;
if let Some(reqire_network_conf) = toml_config
.get("network")
.and_then(|v| v.as_table())
.and_then(|v| v.get("reqire_network"))
.and_then(|v| v.as_bool())
{
log::debug!("Config value reqire_network read {}", reqire_network_conf);
reqire_network = reqire_network_conf;
} else {
log::error!("Error parsing network config. Using default values.");
}
let spinner_frames = let spinner_frames =
apng::Frames::from_bytes(crate::kira_theming::get_spiner_bytes()).unwrap(); apng::Frames::from_bytes(crate::kira_theming::get_spiner_bytes()).unwrap();
@@ -125,17 +111,19 @@ impl NetworkStage {
internet_active: false, internet_active: false,
state: State::Cheking, state: State::Cheking,
use_net_settings: true, use_net_settings: true,
reqire_network: reqire_network,
spinner_frames: spinner_frames, spinner_frames: spinner_frames,
status_message: t!("network.checking").into(), status_message: t!("network.checking").into(),
k_config: k_config,
} }
} }
fn gen_result(&self) -> StageResult { fn gen_result(&self) -> KiraConfig {
StageResult::NetworkStageResult(NetworkStageResult { let mut k_config = self.k_config.clone();
k_config.res_network = Some(NetworkStageResult {
internet_active: self.internet_active, internet_active: self.internet_active,
use_net_settings: self.use_net_settings, use_net_settings: self.use_net_settings,
}) });
k_config
} }
pub fn update(&mut self, message: Message) -> UpdateResult { pub fn update(&mut self, message: Message) -> UpdateResult {
@@ -176,7 +164,7 @@ impl NetworkStage {
pub fn view(&self) -> iced::Element<'_, Message> { pub fn view(&self) -> iced::Element<'_, Message> {
let next_button = let next_button =
if (self.state == State::Cheking) || (!self.internet_active && self.reqire_network) { if (self.state == State::Cheking) || (!self.internet_active && REQIRE_NETWORK) {
widget::button(widget::text(t!("button.next"))) widget::button(widget::text(t!("button.next")))
} else { } else {
widget::button(widget::text(t!("button.next"))).on_press(Message::Next) widget::button(widget::text(t!("button.next"))).on_press(Message::Next)
+51 -48
View File
@@ -24,11 +24,13 @@ use crate::kira_color_bar;
use crate::kira_disk_layout::{BlkDev, FSType, PartInfo, PartLayout}; use crate::kira_disk_layout::{BlkDev, FSType, PartInfo, PartLayout};
use crate::kira_size::KiraSize; use crate::kira_size::KiraSize;
use crate::kira_sysinfo; use crate::kira_sysinfo;
use crate::stage::{StageAction, StageResult}; use crate::stage::{KiraConfig, StageAction};
use iced::{Alignment, Color, Element, Length, widget}; use iced::{Alignment, Color, Element, Length, widget};
use log; use log;
use rust_i18n::t; use rust_i18n::t;
use toml::Table;
const MIN_DISK_SIZE_MB: u64 = 8192;
const EFI_SIZE_MB: u64 = 128;
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SwapMode { pub enum SwapMode {
@@ -69,7 +71,7 @@ fn part_type_to_color(t: &FSType) -> Color {
} }
/// Converts PartInfo into data for ColorBar widget /// Converts PartInfo into data for ColorBar widget
/// ///
fn part_to_ct_params(part: &PartInfo, dev_size: KiraSize) -> (String, u16, Color) { fn part_to_ct_params(part: &PartInfo, dev_size: KiraSize) -> (String, u16, Color) {
let fill_ratio: u16 = ((part.size.b() as f32 / dev_size.b() as f32) * 11.0) as u16; let fill_ratio: u16 = ((part.size.b() as f32 / dev_size.b() as f32) * 11.0) as u16;
let fill_ratio = fill_ratio.max(1); let fill_ratio = fill_ratio.max(1);
@@ -77,8 +79,6 @@ fn part_to_ct_params(part: &PartInfo, dev_size: KiraSize) -> (String, u16, Color
(part.to_string(), fill_ratio, part_color) (part.to_string(), fill_ratio, part_color)
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct PartitionStageResult { pub struct PartitionStageResult {
pub swap_mode: SwapMode, pub swap_mode: SwapMode,
@@ -91,8 +91,6 @@ pub struct PartitionStageResult {
pub part_layout: PartLayout, pub part_layout: PartLayout,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct PartitionStage { pub struct PartitionStage {
device: Option<BlkDev>, device: Option<BlkDev>,
@@ -110,10 +108,9 @@ pub struct PartitionStage {
generated_part_layout: Option<PartLayout>, generated_part_layout: Option<PartLayout>,
system_ram_size: KiraSize, system_ram_size: KiraSize,
vram_of_all_gpus_size: KiraSize, vram_of_all_gpus_size: KiraSize,
k_config: KiraConfig,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Message { pub enum Message {
SelectDevice(BlkDev), SelectDevice(BlkDev),
@@ -129,27 +126,12 @@ pub enum Message {
} }
impl PartitionStage { impl PartitionStage {
pub fn new(toml_config: &Table) -> Result<Self, String> { pub fn new(k_config: KiraConfig) -> Result<Self, String> {
let maybe_dev_list = BlkDev::list_sys_blk_dev(); let maybe_dev_list = BlkDev::list_sys_blk_dev();
log::info!("hiii from partition"); log::info!("hiii from partition");
let mut min_disk_size_mb = 8192;
let mut efi_size_mb = 128;
if let Some(part_table) = toml_config
.get("partition")
.and_then(|v| v.as_table()) {
min_disk_size_mb = part_table.get("min_disk_size_mb") let min_disk_size: KiraSize = KiraSize::new_mb(MIN_DISK_SIZE_MB);
.and_then(|v| v.as_integer()) let efi_size: KiraSize = KiraSize::new_mb(EFI_SIZE_MB);
.unwrap_or(8192);
efi_size_mb = part_table.get("efi_size_mb")
.and_then(|v| v.as_integer())
.unwrap_or(128);
}
let min_disk_size: KiraSize = KiraSize::new_mb(min_disk_size_mb.try_into().unwrap_or(8192));
let efi_size: KiraSize = KiraSize::new_mb(efi_size_mb.try_into().unwrap_or(128));
let sec_boot_setup = match kira_sysinfo::get_secure_boot_status() { let sec_boot_setup = match kira_sysinfo::get_secure_boot_status() {
Ok(sb_status) => sb_status.setup_mode, Ok(sb_status) => sb_status.setup_mode,
@@ -192,9 +174,10 @@ impl PartitionStage {
efi_size: efi_size, efi_size: efi_size,
selected_disk_parts: None, selected_disk_parts: None,
generated_disk_parts: None, generated_disk_parts: None,
generated_part_layout:None, generated_part_layout: None,
system_ram_size: system_ram_size, system_ram_size: system_ram_size,
vram_of_all_gpus_size: vram_of_all_gpus_size, vram_of_all_gpus_size: vram_of_all_gpus_size,
k_config: k_config,
}) })
} }
Err(ex) => Err(ex), Err(ex) => Err(ex),
@@ -240,8 +223,16 @@ impl PartitionStage {
fn gen_layout(&mut self) { fn gen_layout(&mut self) {
if let Some(dev) = self.device.clone() { if let Some(dev) = self.device.clone() {
let swap_size: KiraSize = self.get_swap_size(); let swap_size: KiraSize = self.get_swap_size();
let patr_layout = PartLayout::gen_kira_layout(dev.clone(), self.efi_size, swap_size); let patr_layout = PartLayout::gen_kira_layout(
self.generated_disk_parts = Some(patr_layout.part_list dev.clone(),
self.efi_size,
swap_size,
None,
Some("lz4".into()),
);
self.generated_disk_parts = Some(
patr_layout
.part_list
.iter() .iter()
.map(|part_info| part_to_ct_params(part_info, dev.size)) .map(|part_info| part_to_ct_params(part_info, dev.size))
.collect(), .collect(),
@@ -250,14 +241,24 @@ impl PartitionStage {
} }
} }
fn gen_result(&self) -> StageResult { fn gen_result(&mut self) -> KiraConfig {
let disk_layout = self.generated_part_layout.clone().expect("Layout must be generated!"); let disk_layout = self
.generated_part_layout
.clone()
.expect("Layout must be generated!");
StageResult::PartitionStageResult(PartitionStageResult { swap_mode: self.swap_mode.clone().unwrap(), self.k_config.res_partition = Some(PartitionStageResult {
swap_size: self.get_swap_size(), efi_size: self.efi_size, swap_mode: self.swap_mode.clone().unwrap(),
use_zram: self.use_zram, secure_boot: self.secure_boot, encrypt_drive: true, swap_size: self.get_swap_size(),
password: Some("123456".to_string()), part_layout: disk_layout }) efi_size: self.efi_size,
use_zram: self.use_zram,
secure_boot: self.secure_boot,
encrypt_drive: true,
password: Some("123456".to_string()),
part_layout: disk_layout,
});
self.k_config.clone()
} }
pub fn update(&mut self, message: Message) -> StageAction { pub fn update(&mut self, message: Message) -> StageAction {
@@ -290,25 +291,25 @@ impl PartitionStage {
self.device = Some(dev); self.device = Some(dev);
self.gen_layout(); self.gen_layout();
StageAction::None StageAction::None
}, }
Message::SelectSwapMode(sm) => { Message::SelectSwapMode(sm) => {
self.swap_mode = Some(sm); self.swap_mode = Some(sm);
self.gen_layout(); self.gen_layout();
StageAction::None StageAction::None
}, }
Message::ToggleSecureBoot(t) => { Message::ToggleSecureBoot(t) => {
self.secure_boot = t; self.secure_boot = t;
StageAction::None StageAction::None
}, }
Message::ToggleEncrypDrive(t) => { Message::ToggleEncrypDrive(t) => {
self.encrypt_drive = t; self.encrypt_drive = t;
StageAction::None StageAction::None
}, }
Message::ToggleZram(t) => { Message::ToggleZram(t) => {
self.use_zram = t; self.use_zram = t;
self.gen_layout(); self.gen_layout();
StageAction::None StageAction::None
}, }
Message::SwapSizeIncrement => { Message::SwapSizeIncrement => {
self.custom_swap_size_mb = (self.custom_swap_size_mb / 1024u32) self.custom_swap_size_mb = (self.custom_swap_size_mb / 1024u32)
.strict_mul(1024u32) .strict_mul(1024u32)
@@ -316,7 +317,7 @@ impl PartitionStage {
self.custom_swap_size_str = format!("{}MB", self.custom_swap_size_mb); self.custom_swap_size_str = format!("{}MB", self.custom_swap_size_mb);
self.gen_layout(); self.gen_layout();
StageAction::None StageAction::None
}, }
Message::SwapSizeDecrement => { Message::SwapSizeDecrement => {
self.custom_swap_size_mb = (self.custom_swap_size_mb / 1024u32) self.custom_swap_size_mb = (self.custom_swap_size_mb / 1024u32)
.strict_mul(1024u32) .strict_mul(1024u32)
@@ -324,7 +325,7 @@ impl PartitionStage {
self.custom_swap_size_str = format!("{}MB", self.custom_swap_size_mb); self.custom_swap_size_str = format!("{}MB", self.custom_swap_size_mb);
self.gen_layout(); self.gen_layout();
StageAction::None StageAction::None
}, }
Message::SwapSizeFieldChange(f_v) => { Message::SwapSizeFieldChange(f_v) => {
let mut only_num = f_v.trim().to_string(); let mut only_num = f_v.trim().to_string();
only_num.retain(char::is_numeric); only_num.retain(char::is_numeric);
@@ -332,7 +333,7 @@ impl PartitionStage {
self.custom_swap_size_str = format!("{}MB", self.custom_swap_size_mb); self.custom_swap_size_str = format!("{}MB", self.custom_swap_size_mb);
self.gen_layout(); self.gen_layout();
StageAction::None StageAction::None
}, }
Message::Back => StageAction::Back, Message::Back => StageAction::Back,
Message::Next => StageAction::Next(self.gen_result()), Message::Next => StageAction::Next(self.gen_result()),
} }
@@ -374,10 +375,12 @@ impl PartitionStage {
let selected_dev_content = widget::column![selected_dev_text, selected_dev_content]; let selected_dev_content = widget::column![selected_dev_text, selected_dev_content];
let use_sec_boot_checkbox = if self.secure_boot_in_setup_mode { let use_sec_boot_checkbox = if self.secure_boot_in_setup_mode {
widget::checkbox(self.secure_boot)
.label(t!("partition.use_secure_boot"))
.on_toggle(Message::ToggleSecureBoot)
} else {
widget::checkbox(self.secure_boot).label(t!("partition.use_secure_boot")) widget::checkbox(self.secure_boot).label(t!("partition.use_secure_boot"))
.on_toggle(Message::ToggleSecureBoot) };
}
else {widget::checkbox(self.secure_boot).label(t!("partition.use_secure_boot"))};
widget::column![ widget::column![
widget::container( widget::container(
+8 -5
View File
@@ -18,7 +18,7 @@
This is Security stage, setup users logins and such This is Security stage, setup users logins and such
*/ */
use crate::stage::{StageAction, StageResult}; use crate::stage::{StageAction, KiraConfig};
use iced::{Alignment, Color, widget}; use iced::{Alignment, Color, widget};
use rust_i18n::t; use rust_i18n::t;
@@ -69,6 +69,7 @@ pub struct SecurityStage {
root_pass_is_secure: bool, root_pass_is_secure: bool,
user_password_strenght: PasswordStrenght, user_password_strenght: PasswordStrenght,
root_password_strenght: PasswordStrenght, root_password_strenght: PasswordStrenght,
k_config: KiraConfig,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@@ -101,7 +102,7 @@ fn retain_first_n(s: &str, n: usize) -> &str {
} }
impl SecurityStage { impl SecurityStage {
pub fn new() -> Self { pub fn new(k_config: KiraConfig) -> Self {
Self { Self {
user_name: "".into(), user_name: "".into(),
user_full_name: "".into(), user_full_name: "".into(),
@@ -112,16 +113,18 @@ impl SecurityStage {
root_pass_is_secure: true, root_pass_is_secure: true,
user_password_strenght: PasswordStrenght::Low, user_password_strenght: PasswordStrenght::Low,
root_password_strenght: PasswordStrenght::Low, root_password_strenght: PasswordStrenght::Low,
k_config: k_config,
} }
} }
fn gen_result(&self) -> StageResult { fn gen_result(&mut self) -> KiraConfig {
StageResult::SecurityStageResult(SecurityStageResult { self.k_config.res_security = Some(SecurityStageResult {
user_name: self.user_name.clone(), user_name: self.user_name.clone(),
user_full_name: self.user_full_name.clone(), user_full_name: self.user_full_name.clone(),
user_password: self.user_password.clone(), user_password: self.user_password.clone(),
root_password: self.root_password.clone(), root_password: self.root_password.clone(),
}) });
self.k_config.clone()
} }
pub fn update(&mut self, message: Message) -> StageAction { pub fn update(&mut self, message: Message) -> StageAction {
+9 -5
View File
@@ -18,7 +18,7 @@
This is TimeZone stage, used to select timezone This is TimeZone stage, used to select timezone
*/ */
use crate::stage::{StageAction, StageResult}; use crate::stage::{KiraConfig, StageAction};
use iced::{Alignment, Length, widget}; use iced::{Alignment, Length, widget};
use log; use log;
use rust_i18n::t; use rust_i18n::t;
@@ -58,6 +58,7 @@ pub struct TimeZoneStage {
zone_id: Option<usize>, zone_id: Option<usize>,
selected_zone: Option<TimeZoneData>, selected_zone: Option<TimeZoneData>,
selected_zone_text: String, selected_zone_text: String,
k_config: KiraConfig,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@@ -105,7 +106,7 @@ fn get_timezones_blocking() -> Result<Vec<TimeZoneData>, String> {
} }
impl TimeZoneStage { impl TimeZoneStage {
pub fn new() -> Self { pub fn new(k_config: KiraConfig) -> Self {
match get_timezones_blocking() { match get_timezones_blocking() {
Ok(time_zones_data_list) => { Ok(time_zones_data_list) => {
let mut time_zones_map: HashMap<String, Vec<String>> = HashMap::new(); let mut time_zones_map: HashMap<String, Vec<String>> = HashMap::new();
@@ -130,6 +131,7 @@ impl TimeZoneStage {
zone_id: None, zone_id: None,
selected_zone: None, selected_zone: None,
selected_zone_text: String::new(), selected_zone_text: String::new(),
k_config: k_config,
} }
} }
Err(ex) => { Err(ex) => {
@@ -145,18 +147,20 @@ impl TimeZoneStage {
zone_id: None, zone_id: None,
selected_zone: None, selected_zone: None,
selected_zone_text: String::new(), selected_zone_text: String::new(),
k_config: k_config,
} }
} }
} }
} }
fn gen_result(&self) -> StageResult { fn gen_result(&mut self) -> KiraConfig {
StageResult::TimeZoneStageResult(TimeZoneStageResult { self.k_config.res_timezone = Some(TimeZoneStageResult {
time_zone: self time_zone: self
.selected_zone .selected_zone
.clone() .clone()
.expect("Timezone must be selected!"), .expect("Timezone must be selected!"),
}) });
self.k_config.clone()
} }
pub fn update(&mut self, message: Message) -> StageAction { pub fn update(&mut self, message: Message) -> StageAction {
+18 -15
View File
@@ -20,7 +20,7 @@
use crate::{ use crate::{
kira_theming, kira_theming,
stage::{StageAction, StageResult}, stage::{KiraConfig, StageAction},
}; };
use iced::{Alignment, widget}; use iced::{Alignment, widget};
use rust_i18n::t; use rust_i18n::t;
@@ -37,18 +37,19 @@ impl std::fmt::Display for LocData {
} }
} }
#[derive(Debug, Clone)]
pub struct WelcomeStage {
locale: Option<LocData>,
locales: Vec<LocData>,
}
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct WelcomeStageResult { pub struct WelcomeStageResult {
pub loc_code: String, pub loc_code: String,
pub loc_name: String, pub loc_name: String,
} }
#[derive(Debug, Clone)]
pub struct WelcomeStage {
locale: Option<LocData>,
locales: Vec<LocData>,
k_config: KiraConfig,
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Message { pub enum Message {
SelectLocale(LocData), SelectLocale(LocData),
@@ -57,7 +58,7 @@ pub enum Message {
} }
impl WelcomeStage { impl WelcomeStage {
pub fn new() -> Self { pub fn new(k_config: KiraConfig) -> Self {
Self { Self {
locale: Some(LocData { locale: Some(LocData {
name: "English".into(), name: "English".into(),
@@ -70,21 +71,23 @@ impl WelcomeStage {
code: s.to_string(), code: s.to_string(),
}) })
.collect(), .collect(),
k_config: k_config,
} }
} }
fn gen_result(&self) -> StageResult { fn gen_result(&mut self) -> KiraConfig {
if let Some(loc) = &self.locale { self.k_config.res_welcome = Some(if let Some(loc) = &self.locale {
StageResult::WelcomeStageResult(WelcomeStageResult { WelcomeStageResult {
loc_code: loc.code.clone(), loc_code: loc.code.clone(),
loc_name: loc.name.clone(), loc_name: loc.name.clone(),
}) }
} else { } else {
StageResult::WelcomeStageResult(WelcomeStageResult { WelcomeStageResult {
loc_code: "en".to_string(), loc_code: "en".to_string(),
loc_name: "English".to_string(), loc_name: "English".to_string(),
}) }
} });
self.k_config.clone()
} }
pub fn update(&mut self, message: Message) -> StageAction { pub fn update(&mut self, message: Message) -> StageAction {