Finished locales stage, and work on theming.

This commit is contained in:
2026-05-03 18:07:06 +02:00
parent a1263e7056
commit cf7b9ace08
7 changed files with 167 additions and 241 deletions
+28 -23
View File
@@ -1,25 +1,22 @@
// <Kira Installer - universal Linux installer.>
// Copyright (C) <2026> <Kira Foundation>
// <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 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 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 License stage. Used to inform user about program legal status.
*/
This is License stage. Used to inform user about program legal status.
*/
use iced::{Alignment, widget};
@@ -74,12 +71,20 @@ impl LicenseStage {
widget::button(widget::text(t!("license.button.decline"))).on_press(Message::Decline);
widget::column![
widget::container(widget::column![
widget::text(t!("license.accept_text")),
widget::container(widget::text(t!("license.license")))
.padding(10)
.style(widget::container::bordered_box)
].align_x(Alignment::Center).padding(20).spacing(10))
widget::container(
widget::column![
widget::text(t!("license.accept_text")).font(iced::Font {
weight: iced::font::Weight::Bold,
..iced::Font::DEFAULT
}),
widget::container(widget::text(t!("license.license")))
.padding(10)
.style(widget::container::bordered_box)
]
.align_x(Alignment::Center)
.padding(20)
.spacing(15)
)
.height(iced::Length::Fill)
.width(iced::Length::Fill)
.align_x(Alignment::Center)
+52 -41
View File
@@ -24,14 +24,14 @@ use crate::{
};
use iced::{Alignment, widget};
use rust_i18n::t;
use std::{collections::HashMap, default};
use std::collections::HashMap;
const LOCALES_GEN_FILE_NAME: &str = "/etc/locale.gen";
const LOCALES_GEN_START_LINE: usize = 17;
fn default_locale() -> (String, String) {
("C.UTF-8".to_string(), "UTF-8".to_string())
}
// fn default_locale() -> (String, String) {
// ("C.UTF-8".to_string(), "UTF-8".to_string())
// }
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct LocaleData {
@@ -41,20 +41,21 @@ pub struct LocaleData {
impl std::fmt::Display for LocaleData {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{} ({})", self.description, self.code)
write!(f, "{} ({})", self.code, self.description)
}
}
impl LocaleData {
pub fn default() -> Self {
let def = default_locale();
Self {
code: def.0,
description: def.1,
code: "C.UTF-8".into(),
description: "C locale".into(),
}
}
}
/// gets locales list from system "/etc/locale.gen" file
/// Filters out non UTF-8 locales
fn get_locales_codes_list_blocking() -> std::io::Result<Vec<(String, String)>> {
use std::fs::File;
use std::io::{BufReader, Read};
@@ -86,6 +87,7 @@ fn get_locales_codes_list_blocking() -> std::io::Result<Vec<(String, String)>> {
Ok(res)
}
/// Gets locales description from "/usr/share/i18n/locales/" directory.
fn get_locales_description_blocking() -> Result<HashMap<String, String>, String> {
use std::process::Command;
@@ -130,7 +132,7 @@ fn get_locales_description_blocking() -> Result<HashMap<String, String>, String>
#[derive(Debug, Clone)]
pub struct LocaleStage {
lang_locale: Option<LocaleData>,
all_locale: Option<LocaleData>,
formats_locale: Option<LocaleData>,
locales: Vec<LocaleData>,
lang_locale_text: String,
all_locale_text: String,
@@ -139,7 +141,7 @@ pub struct LocaleStage {
#[derive(Debug, Clone)]
pub enum Message {
SelectLangLocale(LocaleData),
SelectAllLocale(LocaleData),
SelectFormatsLocale(LocaleData),
Next,
Back,
}
@@ -151,13 +153,12 @@ impl LocaleStage {
.get_stage("welcome")
.and_then(|v| v.config.and_then(|v| v.get("loc_code").cloned()));
let 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();
// println!("{:?}", raw_loc_descr);
//println!("{:?}", raw_loc_descr);
let locales: Vec<LocaleData> = loc_codes
let locales: Vec<LocaleData> = raw_loc_codes
.iter()
.filter_map(|(code, _)| {
code.split_once('.')
@@ -186,8 +187,8 @@ impl LocaleStage {
LocaleData::default()
};
println!("lang_match {:?}", lang_match);
println!("loc_codes {:?}", loc_codes);
//println!("lang_match {:?}", lang_match);
//println!("loc_codes {:?}", raw_loc_codes);
// let locale = locales.iter().find(|l| l.code == lang_match.0).cloned();
@@ -203,7 +204,7 @@ impl LocaleStage {
);
Self {
lang_locale: Some(lang_match.clone()),
all_locale: Some(lang_match),
formats_locale: Some(lang_match),
locales: locales,
lang_locale_text: lang_locale_text,
all_locale_text: all_locale_text,
@@ -212,7 +213,7 @@ impl LocaleStage {
fn gen_result(&self) -> StageResult {
if let Some(lang_locale) = &self.lang_locale
&& let Some(all_locale) = &self.all_locale
&& let Some(formats_locale) = &self.formats_locale
{
StageResult {
name: "locale".to_string(),
@@ -222,25 +223,23 @@ impl LocaleStage {
ConfigValue::String(lang_locale.code.clone()),
),
(
"all_locale".to_string(),
ConfigValue::String(all_locale.code.clone()),
"formats_locale".to_string(),
ConfigValue::String(formats_locale.code.clone()),
),
])),
resuts: None,
error: None,
}
} else {
let loc = LocaleData::default();
StageResult {
name: "locale".to_string(),
config: Some(HashMap::from([
(
"lang_locale".to_string(),
ConfigValue::String(default_locale().0),
),
(
"all_locale".to_string(),
ConfigValue::String(default_locale().0),
ConfigValue::String(loc.code.clone()),
),
("formats_locale".to_string(), ConfigValue::String(loc.code)),
])),
resuts: None,
error: None,
@@ -256,10 +255,10 @@ impl LocaleStage {
self.lang_locale = Some(loc);
StageAction::None
}
Message::SelectAllLocale(loc) => {
Message::SelectFormatsLocale(loc) => {
self.all_locale_text =
format!("{}: {}", t!("locale.select_formats_locale"), loc.code);
self.all_locale = Some(loc);
self.formats_locale = Some(loc);
StageAction::None
}
Message::Back => StageAction::Back,
@@ -280,20 +279,32 @@ impl LocaleStage {
widget::image(welcome_logo_handle)
.width(iced::Pixels(128.0))
.height(iced::Pixels(128.0)),
widget::column![
widget::text(self.lang_locale_text.as_str()),
widget::pick_list(
self.locales.clone(),
self.lang_locale.clone(),
Message::SelectLangLocale,
),
widget::text(self.all_locale_text.as_str()),
widget::pick_list(
self.locales.clone(),
self.all_locale.clone(),
Message::SelectAllLocale,
)
]
widget::container(
widget::column![
widget::text(self.lang_locale_text.as_str()),
widget::pick_list(
self.locales.clone(),
self.lang_locale.clone(),
Message::SelectLangLocale,
)
]
.spacing(5)
)
.style(widget::container::bordered_box)
.padding(5),
widget::container(
widget::column![
widget::text(self.all_locale_text.as_str()),
widget::pick_list(
self.locales.clone(),
self.formats_locale.clone(),
Message::SelectFormatsLocale,
)
]
.spacing(5)
)
.style(widget::container::bordered_box)
.padding(5)
]
.padding(10)
.spacing(10)
+20 -9
View File
@@ -29,7 +29,6 @@ use crate::stage;
use crate::stage::StageResult;
#[derive(Debug, Clone)]
#[derive(PartialEq, Eq)]
pub enum State {
Cheking,
@@ -50,6 +49,7 @@ pub struct NetworkStage {
use_net_settings: bool,
reqire_network: bool,
spinner_frames: apng::Frames,
logo_handle: widget::image::Handle,
status_message: String,
}
@@ -113,7 +113,10 @@ impl NetworkStage {
let spinner_frames =
apng::Frames::from_bytes(crate::kira_theming::get_spiner_bytes()).unwrap();
let logo_handle = widget::image::Handle::from_bytes(crate::kira_theming::get_logo_bytes());
Self {
logo_handle: logo_handle,
internet_active: false,
state: State::Cheking,
use_net_settings: false,
@@ -178,12 +181,12 @@ impl NetworkStage {
}
pub fn view(&self) -> iced::Element<'_, Message> {
let next_button = if (self.state == State::Cheking) || (!self.internet_active && self.reqire_network) {
widget::button(widget::text(t!("button.next")))
}
else {
widget::button(widget::text(t!("button.next"))).on_press(Message::Next)
};
let next_button =
if (self.state == State::Cheking) || (!self.internet_active && self.reqire_network) {
widget::button(widget::text(t!("button.next")))
} else {
widget::button(widget::text(t!("button.next"))).on_press(Message::Next)
};
let (back_button, check_button, reuse_checkbox) = match self.state {
State::Cheking => (
@@ -202,8 +205,16 @@ impl NetworkStage {
};
let spinner_container = match self.state {
State::Cheking => widget::container(apng(&self.spinner_frames)),
State::Normal => widget::container(widget::space().height(128).width(128)),
State::Cheking => widget::container(
apng(&self.spinner_frames)
.width(iced::Pixels(128.0).into())
.height(iced::Pixels(128.0).into()),
),
State::Normal => widget::container(
widget::image(&self.logo_handle)
.width(iced::Pixels(128.0))
.height(iced::Pixels(128.0)),
),
};
let info_column = widget::column![