From e015a541f9c1627be9e185b1c402c8157bf952a248be447b926d62313dad3d69 Mon Sep 17 00:00:00 2001 From: Kira Date: Fri, 1 May 2026 00:29:15 +0200 Subject: [PATCH] TimeZone stage allmost done. --- Cargo.toml | 4 +- src/locales/en.json | 4 +- src/main.rs | 7 +- src/stages/license/mod.rs | 2 +- src/stages/network/mod.rs | 2 +- src/stages/timezone/mod.rs | 133 ++++++++++++++++------------- src/stages/timezone/scroll_list.rs | 110 ++++++++++++++++++++++++ 7 files changed, 194 insertions(+), 68 deletions(-) create mode 100644 src/stages/timezone/scroll_list.rs diff --git a/Cargo.toml b/Cargo.toml index 75d1bc8..0db4d35 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ rust-i18n = "3" toml = "1" [profile.release] -lto = true -codegen-units = 1 +#lto = true +codegen-units = 16 opt-level = 3 strip = true diff --git a/src/locales/en.json b/src/locales/en.json index 1c7ca9a..67f3f27 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -18,8 +18,8 @@ "network.no_connection": "Network inactive.", "network.check_error": "Error while cheking network connection.", "network.button.check": "Check Network", - "timezone.select_region": "Select region:", - "timezone.select_timezone": "Select time zone:", + "timezone.selected_timezone": "Selected timezone:", + "timezone.select_timezone": "Please select preffered time zone", "timezone.init_error": "Erro getting time zones data from system." } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index f2bd347..b82ebc1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -184,7 +184,12 @@ fn update(k_state: &mut KiraState, message: Message) -> Task { iced::exit() } StageAction::Abort(_) => iced::exit(), - StageAction::Back => iced::exit(), + StageAction::Back => { + k_state.config.config_trail.pop(); + k_state.current_view = + Views::Network(network::NetworkStage::new(&k_state.toml_config)); + Task::done(Message::Network(network::Message::CheckNetwork)) + } StageAction::None => Task::none(), } } else { diff --git a/src/stages/license/mod.rs b/src/stages/license/mod.rs index 2dc0400..24b3a41 100644 --- a/src/stages/license/mod.rs +++ b/src/stages/license/mod.rs @@ -43,7 +43,7 @@ pub enum Message { //['ace', 'af', 'sq', 'ar', 'an', 'hy', 'as', 'ay', 'az', 'ba', 'eu', 'be', 'bn', 'bho', 'bs', 'br', 'bg', 'my', 'yue', 'ca', 'ceb', 'zh-Hans', 'zh-Hant', 'hr', 'cs', 'da', 'prs', 'nl', 'en-US', 'en-GB', 'eo', 'et', 'fi', 'fr', 'gl', 'ka', 'de', 'el', 'gn', 'gu', 'ht', 'ha', 'he', 'hi', 'hu', 'is', 'ig', 'id', 'ga', 'it', 'ja', 'jv', 'pam', 'kk', 'gom', 'ko', 'kmr', 'ckb', 'ky', 'la', 'lv', 'ln', 'lt', 'lmo', 'lb', 'mk', 'mai', 'mg', 'ms', 'ml', 'mt', 'mi', 'mr', 'mn', 'ne', 'nb', 'oc', 'om', 'pag', 'ps', 'fa', 'pl', 'pt-PT', 'pt-BR', 'pa', 'qu', 'ro', 'ru', 'sa', 'sr', 'st', 'scn', 'sk', 'sl', 'es', 'es-419', 'su', 'sw', 'sv', 'tl', 'tg', 'ta', 'tt', 'te', 'ts', 'tn', 'tr', 'tk', 'uk', 'ur', 'uz', 'vi', 'cy', 'wo', 'xh', 'yi', 'zu'] // -const license_text: &str = include_str!("gpl-3.0.txt"); +//const LICENSE_TEXT: &str = include_str!("gpl-3.0.txt"); impl LicenseStage { fn accepted() -> StageResult { diff --git a/src/stages/network/mod.rs b/src/stages/network/mod.rs index 4d8ce12..93d1e59 100644 --- a/src/stages/network/mod.rs +++ b/src/stages/network/mod.rs @@ -71,7 +71,7 @@ pub enum UpdateResult { fn check_connection_blocking() -> CheckResult { use std::process::Command; - std::thread::sleep(std::time::Duration::from_secs(5)); + std::thread::sleep(std::time::Duration::from_secs(1)); match Command::new("nm-online").arg("-q").status() { Ok(status) => { diff --git a/src/stages/timezone/mod.rs b/src/stages/timezone/mod.rs index 58a1810..78a24d9 100644 --- a/src/stages/timezone/mod.rs +++ b/src/stages/timezone/mod.rs @@ -19,10 +19,12 @@ */ use crate::stage::{ConfigValue, StageAction, StageResult}; -use iced::{Alignment, widget}; +use iced::{Alignment, Length, widget}; use rust_i18n::t; use std::collections::HashMap; +mod scroll_list; + #[derive(Debug, Clone, PartialEq, Eq)] pub struct TimeZoneData { region: String, @@ -30,7 +32,8 @@ pub struct TimeZoneData { } impl TimeZoneData { - fn to_string(&self) -> String { + + fn to_full_code(&self) -> String { format!("{}/{}", self.region, self.zone) } fn from_str(s: &str) -> Option { @@ -38,30 +41,30 @@ impl TimeZoneData { let (region, zone) = s.split_at(idx); Some(Self { region: region.into(), - zone: zone.into(), + zone: zone.trim_start_matches('/').into(), }) } } impl std::fmt::Display for TimeZoneData { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}/{}", self.region, self.zone) + write!(f, "{}", self.zone) } } #[derive(Debug, Clone)] pub struct TimeZoneStage { - time_zone: Option, - time_zone_region: Option, time_zones: Result>, String>, regions: Vec, + region_id: Option, zones: Vec, + zone_id: Option, } #[derive(Debug, Clone)] pub enum Message { - SelectRegion(String), - SelectZone(TimeZoneData), + SelectRegion(scroll_list::ListViewMessage), + SelectZone(scroll_list::ListViewMessage), Next, Back, } @@ -113,36 +116,45 @@ impl TimeZoneStage { Self { regions: time_zones.keys().cloned().collect(), zones: tzs.clone(), - time_zone: None, - time_zone_region: None, time_zones: Ok(time_zones), + region_id: None, + zone_id: None, } } - Err(ex) => { println!( "Exception while trying to get time zones list from system {}", ex ); Self { - time_zone: None, - time_zone_region: None, time_zones: Err(ex), regions: Vec::new(), zones: Vec::new(), + region_id: None, + zone_id: None, } } } } fn gen_result(&self) -> StageResult { - if let Some(tz) = &self.time_zone { + if let Some(tz_id) = self.zone_id { + let time_zone = &self.zones[tz_id]; StageResult { name: "time_zone".to_string(), config: Some(HashMap::from([ - ("name".to_string(), ConfigValue::String(tz.to_string())), - ("region".to_string(), ConfigValue::String(tz.region.clone())), - ("zone".to_string(), ConfigValue::String(tz.zone.clone())), + ( + "name".to_string(), + ConfigValue::String(time_zone.to_full_code()), + ), + ( + "region".to_string(), + ConfigValue::String(time_zone.region.clone()), + ), + ( + "zone".to_string(), + ConfigValue::String(time_zone.zone.clone()), + ), ])), resuts: None, error: None, @@ -159,12 +171,20 @@ impl TimeZoneStage { pub fn update(&mut self, message: Message) -> StageAction { match message { - Message::SelectRegion(region) => { - self.time_zone_region = Some(region); + Message::SelectRegion(scroll_list::ListViewMessage::Select(region_id)) => { + let region = self.regions.get(region_id).unwrap(); + self.zones = self + .time_zones + .as_ref() + .unwrap() + .get(region) + .unwrap() + .clone(); + self.region_id = Some(region_id); StageAction::None } - Message::SelectZone(zone) => { - self.time_zone = Some(zone); + Message::SelectZone(scroll_list::ListViewMessage::Select(zone_id)) => { + self.zone_id = Some(zone_id); StageAction::None } Message::Next => StageAction::Next(self.gen_result()), @@ -173,48 +193,39 @@ impl TimeZoneStage { } pub fn view(&self) -> iced::Element<'_, Message> { - let (next_button, main_content) = match &self.time_zones { - Ok(time_zones) => ( - widget::button(widget::text(t!("button.next"))).on_press(Message::Next), - widget::container( - widget::column![ - widget::text(t!("timezone.select_timezone")), - widget::row![ - widget::text(t!("timezone.select_region")), - widget::pick_list( - self.regions.clone(), - self.time_zone_region.clone(), - Message::SelectRegion, - ) - .placeholder("Select Region") - ], - widget::row![ - widget::text(t!("timezone.select_timezone")), - widget::pick_list( - time_zones - .get( - self.time_zone_region - .clone() - .unwrap_or("Etc".into()) - .as_str() - ) - .unwrap() - .clone(), - self.time_zone.clone(), - Message::SelectZone, - ) - .placeholder("Select Timezone") - ] + let next_button = if self.zone_id.is_some() { + widget::button(widget::text(t!("button.next"))).on_press(Message::Next) + } else { + widget::button(widget::text(t!("button.next"))) + }; + let main_content = match &self.time_zones { + Ok(_) => { + let mut col = widget::column![ + widget::text(t!("timezone.select_timezone")), + widget::row![ + scroll_list::list_view(&self.regions, self.region_id, Length::Shrink) + .map(Message::SelectRegion), + scroll_list::list_view(&self.zones, self.zone_id, Length::FillPortion(1)) + .map(Message::SelectZone), ] - .padding(10) + .padding(20) .spacing(10) - .align_x(Alignment::Center), - ), - ), - Err(_) => ( - widget::button(widget::text(t!("button.next"))), - widget::container(widget::text(t!("timezone.init_error"))), - ), + .height(Length::Shrink) + ] + .spacing(10) + .align_x(Alignment::Center); + + if let Some(tz_id) = self.zone_id { + col = col.push(widget::text(format!( + "{} {}", + t!("timezone.selected_timezone"), + self.zones[tz_id].to_full_code() + ))) + }; + + widget::container(col) + } + Err(_) => widget::container(widget::text(t!("timezone.init_error"))), }; let back_button = widget::button(widget::text(t!("button.back"))).on_press(Message::Back); diff --git a/src/stages/timezone/scroll_list.rs b/src/stages/timezone/scroll_list.rs new file mode 100644 index 0000000..916acb3 --- /dev/null +++ b/src/stages/timezone/scroll_list.rs @@ -0,0 +1,110 @@ +use std::fmt::Display; + +use iced::widget::{Column, button, container, scrollable, text}; +use iced::{Alignment, Color, Element, Length, Theme}; + +#[derive(Debug, Clone)] +pub enum ListViewMessage { + Select(usize), +} + +fn unselected_button_style(theme: &Theme, status: button::Status) -> button::Style { + //let palette = theme.extended_palette(); + use iced::{Border, border::Radius}; + + match status { + button::Status::Hovered => button::Style { + border: Border { + color: Color::from_rgb(0.8, 0.3, 0.3), + width: 2.0, + radius: Radius::new(5.0), + }, + ..button::primary(theme, status) + }, + button::Status::Active => button::Style { + background: Some(iced::Background::Color(crate::theme::change_lightnes( + &theme.palette().primary, + -0.1, + ))), + ..button::primary(theme, status) + }, + _ => button::primary(theme, status), + } +} + +fn selected_button_style(theme: &Theme, status: button::Status) -> button::Style { + //let palette = theme.extended_palette(); + + match status { + button::Status::Active => button::Style { + background: Some(iced::Background::Color(Color::from_rgb(0.8, 0.3, 0.3))), + ..button::primary(theme, status) + }, + _ => button::Style { + background: Some(iced::Background::Color(Color::from_rgb(0.8, 0.3, 0.3))), + ..button::primary(theme, status) + }, + } +} + +// fn view() -> container::Style { +// container::Style { +// text_color: None, +// background: None, +// border: Border { +// color: Color::BLACK, +// width: 2.0, +// radius: Radius::new(5.0), +// }, +// shadow: None, +// snap: false, +// } +// } + +// fn border_style(theme: &Theme) -> container::Style { +// use iced::{Border, border::Radius}; + +// container::Style { +// border: Border { +// color: Color::from_rgb(0.8, 0.3, 0.3), +// width: 2.0, +// radius: Radius::new(5.0), +// }, +// ..container::bordered_box(theme) +// } +// } + +// Assuming your Item struct or type implements Display or has a text representation +pub fn list_view( + items: &Vec, + selected_id: Option, + container_height: Length, +) -> Element<'_, ListViewMessage> { + let mut column = Column::new() + .spacing(2) + .align_x(Alignment::Center) + .width(Length::Fill); + + for (index, value) in items.iter().enumerate() { + // Create a row for each item, possibly with buttons or other controls + let list_item = if let Some(id) = selected_id + && id == index + { + button(text(value.to_string())).style(selected_button_style) + } else { + button(text(value.to_string())).style(unselected_button_style) + }; + let list_item = list_item + .width(Length::Fill) + .on_press(ListViewMessage::Select(index)); + + column = column.push(list_item); + } + + // Wrap the column in a scrollable widget + container(scrollable(column).width(Length::Fill)) + .style(container::bordered_box) + .height(container_height) + .padding(8) + .into() +}