Work on Network stage and toml config.

This commit is contained in:
2026-04-22 14:21:24 +02:00
parent 33d986df3c
commit 01617374a1
9 changed files with 389 additions and 126 deletions
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 251 KiB

+3
View File
@@ -0,0 +1,3 @@
[network]
reqire_network = true
+3 -2
View File
@@ -10,5 +10,6 @@
"license.license": "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.\n\nThis 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.\n\nYou should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.",
"license.accept_text": "By pressing 'Accept' button you agreening to terms described above.",
"license.button.accept": "Accept",
"license.button.decline": "Decline"
}
"network.reuse_checkbox_caption": "Reuse settings?",
"network.reuse_question": "Do you want to apply current network settings to installing system?"
}
+90 -18
View File
@@ -27,12 +27,15 @@
use iced::widget;
use iced::Alignment;
use std::collections::{HashMap};
use std::path::{PathBuf,Path};
use std::str::FromStr;
use std::process::ExitCode;
use iced::{Element, Task};
use crate::stage::{StageAction, KiraConfig};
use crate::stages::license;
use crate::stages::network;
use crate::stages::welcome;
use crate::stages::welcome::WelcomeStage;
@@ -47,12 +50,15 @@ enum Views {
Start,
Welcome(welcome::WelcomeStage),
License(license::LicenseStage),
Network(stages::network::NetworkStage),
}
enum Message {
Start,
Welcome(welcome::Message),
License(license::Message)
License(license::Message),
Network(stages::network::Message)
}
struct KiraState {
@@ -61,30 +67,70 @@ struct KiraState {
config: KiraConfig,
}
const CONFIG_PATH_STR: &str = "kira_config.toml";
fn load_kira_config(config_path: &str) -> Result<toml::Table, Box<dyn std::error::Error>> {
use std::fs;
use toml::Table;
// 1. Read the file content into a String
let content = fs::read_to_string(config_path)?;
// 2. Parse the string into a Table
let table: Table = content.parse()?;
println!("{:?}", table);
Ok(table)
}
impl KiraState {
fn new(toml_config: toml::Table) -> Self {
Self {
fn boot() -> (Self, Task<Message>) {
(Self {
current_view: Views::Start,
toml_config: toml_config,
toml_config: toml::Table::new(),
config: KiraConfig { config_trail: Vec::new() }
}
}, Task::done(Message::Start))
}
}
// impl KiraState {
// fn new(toml_config: toml::Table) -> Self {
// Self {
// current_view: Views::Start,
// toml_config: toml_config,
// config: KiraConfig { config_trail: Vec::new() }
// }
// }
// }
fn view(k_state: &KiraState) -> Element<'_, Message> {
match &k_state.current_view {
Views::Start => Element::new(widget::space()) ,
Views::Welcome(wellcome_stage) => wellcome_stage.view().map(Message::Welcome),
Views::License(license_stage) => license_stage.view().map(Message::License),
Views::Network(network_stage) => network_stage.view().map(Message::Network),
}
}
fn update(k_state: &mut KiraState, message: Message) -> Task<Message> {
match message {
Message::Start => {
match load_kira_config(CONFIG_PATH_STR) {
Ok(conf) => {
println!("Config loaded!");
k_state.toml_config = conf;
k_state.current_view = Views::Welcome(WelcomeStage::new());
Task::none()
},
Err(ex) => {
println!("Error reading config {}: {}", CONFIG_PATH_STR, ex);
iced::exit()
}
}
},
Message::Welcome(wlc_msg) => {
if let Views::Welcome(wlc_view) = &mut k_state.current_view {
let action = wlc_view.update(wlc_msg);
@@ -101,7 +147,8 @@ fn update(k_state: &mut KiraState, message: Message) -> Task<Message> {
match action {
StageAction::Next(license_res) => {
k_state.config.config_trail.push(license_res);
iced::exit()
k_state.current_view = Views::Network(network::NetworkStage::new(&k_state.toml_config));
Task::none()
},
StageAction::Abort(_) => iced::exit(),
StageAction::Back => iced::exit(),
@@ -111,6 +158,15 @@ fn update(k_state: &mut KiraState, message: Message) -> Task<Message> {
else {
Task::none()
}
},
Message::Network(network_message) => {
if let Views::Network(network_view) = &mut k_state.current_view {
Task::none()
}
else {
Task::none()
}
}
}
}
@@ -119,18 +175,34 @@ fn update(k_state: &mut KiraState, message: Message) -> Task<Message> {
// pub fn main_interface() -> iced::Result {
// iced::run(WellcomeStage::update, WellcomeStage::view)
// }
pub fn main() -> iced::Result {
use toml;
let app_init = || {
let mut k_state = KiraState::new(toml::Table::new());
k_state.current_view = Views::Welcome(WelcomeStage::new());
k_state
};
pub fn main() -> ExitCode {
iced::application(app_init, update, view)
// let app_init = || {
// let mut k_state = KiraState::default()
// k_state.current_view = Views::Welcome(WelcomeStage::new());
// k_stateapp_init
// };
let iced_result = iced::application(KiraState::boot, update, view)
.window(iced::window::Settings {
icon: Some(
iced::window::icon::from_file_data(
include_bytes!("icon.png"),
None,
)
.expect("icon should be a valid PNG"),
),
..Default::default()
})
.centered()
.theme(theme::main_theme())
.run()
.run();
match iced_result {
Ok(()) => ExitCode::SUCCESS,
Err(_) => ExitCode::from(42), // Custom error code
}
}
+2 -1
View File
@@ -16,4 +16,5 @@
pub mod welcome;
pub mod license;
pub mod license;
pub mod network;
+158
View File
@@ -0,0 +1,158 @@
// <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/>.
/*
This is Network stage. Chiking if internet is active and propose to configure it if
it needed for installation to process.
*/
use toml::Table;
use iced::{Alignment, widget};
use rust_i18n::t;
use std::collections::HashMap;
use crate::stage;
use crate::stage::StageResult;
#[derive(Debug, Clone)]
pub enum State {
Init,
Cheking,
ConnOK,
ConnBad,
CheckFailed,
}
#[derive(Debug, Clone)]
pub struct NetworkStage {
internet_active: bool,
state: State,
use_net_settings: bool,
reqire_network: bool,
}
#[derive(Debug, Clone)]
pub enum Message {
Next,
Back,
StateChange(State),
UseSettingsTogle(bool)
}
impl NetworkStage {
pub fn new(toml_config: &Table) -> 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())
{
println!("Config value reqire_network read {}", reqire_network_conf);
reqire_network = reqire_network_conf;
}
else {
println!("Error parsing network config. Using default values.");
}
Self {
internet_active: false,
state: State::Init,
use_net_settings: false,
reqire_network: reqire_network
}
}
fn check_connected(&mut self) -> Result<bool, std::io::Error> {
use std::process::Command;
let status = Command::new("nm-online").arg("-q").status()?;
if status.success() {
self.internet_active = true;
Ok(true)
} else {
self.internet_active = false;
Ok(false)
}
}
fn gen_result(&self) -> StageResult {
StageResult {
name: "network".into(),
config: Some(HashMap::from([(
"accepted".to_string(),
stage::ConfigValue::Bool(true),
)])),
resuts: None,
error: None,
}
}
pub fn update(&mut self, message: Message) -> stage::StageAction {
match message {
Message::Next => stage::StageAction::Next(self.gen_result()),
Message::Back => stage::StageAction::Back,
Message::StateChange(new_state) => {
self.state = new_state;
stage::StageAction::None
},
Message::UseSettingsTogle(toggle) => {
self.use_net_settings = toggle;
stage::StageAction::None
}
}
}
pub fn view(&self) -> iced::Element<'_, Message> {
let next_button =
widget::button(widget::text(t!("button.next"))).on_press(Message::Next);
let back_button = widget::button(widget::text(t!("button.back"))).on_press(Message::Back);
widget::column![
widget::container(
widget::column![
widget::text(t!("network.reuse_question")),
widget::checkbox(self.use_net_settings)
.label(t!("network.reuse_checkbox_caption"))
.on_toggle(Message::UseSettingsTogle)
]
.align_x(Alignment::Center)
.padding(20)
.spacing(5)
)
.height(iced::Length::Fill)
.width(iced::Length::Fill)
.align_x(Alignment::Center)
.align_y(Alignment::Center),
widget::row![
back_button,
widget::space::horizontal(), // Pushes the right button to the far right
next_button
]
.width(iced::Length::Fill)
.align_y(Alignment::End)
.padding(10)
.spacing(10),
]
.align_x(Alignment::Center)
.into()
}
}
+6 -1
View File
@@ -111,7 +111,12 @@ impl WelcomeStage {
self.locale = Some(loc);
StageAction::None
}
Message::Exit => StageAction::Back,
Message::Exit => StageAction::Abort(StageResult {
name: "welcome".to_string(),
config: None,
resuts: None,
error: None,
}),
Message::Next => StageAction::Next(self.gen_result()),
}
}