Language Page

This commit is contained in:
Ward from fusion-voyager-3 2024-08-05 03:25:05 +03:00
parent a49ae2104c
commit d4c0becea5
6 changed files with 488 additions and 30 deletions

View File

@ -37,9 +37,9 @@
"fstab_badfs_swap": ") Must not be swap to be used as [SWAP]!", "fstab_badfs_swap": ") Must not be swap to be used as [SWAP]!",
"fstab_bad_mountpoint": "Filesystem Table Error: Invalid mountpoint: (", "fstab_bad_mountpoint": "Filesystem Table Error: Invalid mountpoint: (",
"fstab_bad_mountpoint_msg": ") Is not a valid mountpoint!", "fstab_bad_mountpoint_msg": ") Is not a valid mountpoint!",
"select_a_language": "Select a language", "select_a_language": "Select a Language",
"please_select_locale": "Please select a locale for the system to use", "please_select_locale": "Please Select a Locale for The System to Use",
"no_locale_selected": "No locale selected", "no_locale_selected": "No Locale selected",
"language": "Language", "language": "Language",
"select_a_keyboard": "Select a keyboard", "select_a_keyboard": "Select a keyboard",
"please_select_keyboard": "Please select a Keyboard layout for the system to use", "please_select_keyboard": "Please select a Keyboard layout for the system to use",
@ -94,5 +94,6 @@
"done": "Done", "done": "Done",
"partitioning": "Partitioning", "partitioning": "Partitioning",
"luks2_password_confirm": "Confirm LUKS Password", "luks2_password_confirm": "Confirm LUKS Password",
"luks_not_match": "The LUKS Passwords do not match!" "luks_not_match": "The LUKS Passwords do not match!",
"search_for_language": "Search for a Language"
} }

View File

@ -1,8 +1,8 @@
use std::path::Path; use std::path::Path;
use gtk::{prelude::*, glib as glib}; use gtk::{prelude::*, glib as glib};
use vte::ffi::VTE_ALIGN_CENTER;
use crate::efi_error_page; use crate::efi_error_page;
use crate::installer_stack_page; use crate::welcome_page;
use crate::language_page;
pub fn build_ui(app: &adw::Application) { pub fn build_ui(app: &adw::Application) {
glib::set_prgname(Some("pikaos_installer")); glib::set_prgname(Some("pikaos_installer"));
@ -47,20 +47,11 @@ pub fn build_ui(app: &adw::Application) {
.build(); .build();
match Path::new("/sys/firmware/efi/efivars").exists() { match Path::new("/sys/firmware/efi/efivars").exists() {
true => { true => welcome_page::welcome_page(&window, &carousel),
let page = installer_stack_page::InstallerStackPage::new();
page.set_page_icon("pika-logo");
page.set_page_title("Title");
page.set_page_subtitle("Subtitle");
let gbox = gtk::Box::new(gtk::Orientation::Vertical, 0);
gbox.append(&gtk::Image::builder().icon_name("pika-logo").build());
page.set_child_widget(&gbox);
carousel.append(&page);
}
_ => efi_error_page::efi_error_page(&window, &carousel) _ => efi_error_page::efi_error_page(&window, &carousel)
} }
//welcome_page(&window, &carousel),
//language_page(&window, &carousel); language_page::language_page(&window, &carousel);
window.present() window.present()
} }

View File

@ -1,5 +1,5 @@
use std::{cell::RefCell, env, rc::Rc, sync::OnceLock}; use std::{cell::RefCell, env, rc::Rc, sync::OnceLock};
use gtk::{prelude::*, subclass::prelude::*, glib as glib}; use gtk::{prelude::*, subclass::prelude::*, glib as glib, Justification};
use adw::{prelude::*, subclass::prelude::*}; use adw::{prelude::*, subclass::prelude::*};
use glib::{clone, subclass::prelude::*, subclass::Signal}; use glib::{clone, subclass::prelude::*, subclass::Signal};
@ -15,6 +15,14 @@ pub struct InstallerStackPage {
#[property(get, set)] #[property(get, set)]
page_subtitle: RefCell<String>, page_subtitle: RefCell<String>,
#[property(get, set)] #[property(get, set)]
back_sensitive: RefCell<bool>,
#[property(get, set)]
next_sensitive: RefCell<bool>,
#[property(get, set)]
back_visible: RefCell<bool>,
#[property(get, set)]
next_visible: RefCell<bool>,
#[property(get, set)]
child_widget: Rc<RefCell<gtk::Box>>, child_widget: Rc<RefCell<gtk::Box>>,
} }
// ANCHOR_END: custom_button // ANCHOR_END: custom_button
@ -45,16 +53,21 @@ impl ObjectImpl for InstallerStackPage {
obj.set_vexpand(true); obj.set_vexpand(true);
// //
let main_box = gtk::Box::new(gtk::Orientation::Horizontal, 0); let main_box = gtk::Box::builder()
.orientation(gtk::Orientation::Horizontal)
.hexpand(true)
.build();
// //
let back_button = gtk::Button::builder() let back_button = gtk::Button::builder()
.icon_name("pan-start-symbolic") .icon_name("pan-start-symbolic")
.valign(gtk::Align::Center) .valign(gtk::Align::Center)
.halign(gtk::Align::Start) .halign(gtk::Align::Start)
.margin_start(5) .sensitive(true)
.visible(true)
.margin_start(10)
.margin_end(5) .margin_end(5)
.tooltip_text(t!("back"))
.build(); .build();
back_button.add_css_class("circular"); back_button.add_css_class("circular");
@ -67,14 +80,27 @@ impl ObjectImpl for InstallerStackPage {
} }
)); ));
obj.bind_property("back_sensitive", &back_button, "sensitive")
.sync_create()
.bidirectional()
.build();
obj.bind_property("back_visible", &back_button, "visible")
.sync_create()
.bidirectional()
.build();
// //
let next_button = gtk::Button::builder() let next_button = gtk::Button::builder()
.icon_name("pan-end-symbolic") .icon_name("pan-end-symbolic")
.valign(gtk::Align::Center) .valign(gtk::Align::Center)
.halign(gtk::Align::End) .halign(gtk::Align::End)
.sensitive(false)
.visible(true)
.margin_start(5) .margin_start(5)
.margin_end(5) .margin_end(10)
.tooltip_text(t!("next"))
.build(); .build();
next_button.add_css_class("circular"); next_button.add_css_class("circular");
@ -88,41 +114,82 @@ impl ObjectImpl for InstallerStackPage {
} }
)); ));
obj.bind_property("next_sensitive", &next_button, "sensitive")
.sync_create()
.bidirectional()
.build();
obj.bind_property("next_visible", &next_button, "visible")
.sync_create()
.bidirectional()
.build();
// //
let content_box = gtk::Box::builder() let content_box = gtk::Box::builder()
.orientation(gtk::Orientation::Vertical) .orientation(gtk::Orientation::Vertical)
.halign(gtk::Align::Center)
.hexpand(true) .hexpand(true)
.build(); .build();
let info_status_page = adw::StatusPage::builder() //
let installer_page_icon = gtk::Image::builder()
.pixel_size(80)
.valign(gtk::Align::Start) .valign(gtk::Align::Start)
.halign(gtk::Align::Center) .halign(gtk::Align::Center)
.hexpand(true) .hexpand(true)
.build(); .build();
info_status_page.add_css_class("compact"); let installer_page_title = gtk::Label::builder()
.valign(gtk::Align::Start)
.halign(gtk::Align::Center)
.hexpand(true)
.wrap(true)
.justify(Justification::Center)
.width_chars(20)
.margin_top(5)
.margin_bottom(5)
.margin_start(5)
.margin_end(5)
.build();
obj.bind_property("page_icon", &info_status_page, "icon_name") installer_page_title.add_css_class("title-1");
let installer_page_subtitle = gtk::Label::builder()
.valign(gtk::Align::Start)
.halign(gtk::Align::Center)
.hexpand(true)
.justify(Justification::Center)
.width_chars(20)
.margin_top(5)
.margin_bottom(5)
.margin_start(5)
.margin_end(5)
.build();
obj.bind_property("page_icon", &installer_page_icon, "icon_name")
.sync_create() .sync_create()
.bidirectional() .bidirectional()
.build(); .build();
obj.bind_property("page_title", &info_status_page, "title") obj.bind_property("page_title", &installer_page_title, "label")
.sync_create() .sync_create()
.bidirectional() .bidirectional()
.build(); .build();
obj.bind_property("page_subtitle", &info_status_page, "description") obj.bind_property("page_subtitle", &installer_page_subtitle, "label")
.sync_create() .sync_create()
.bidirectional() .bidirectional()
.build(); .build();
let child_bin = adw::Bin::builder() let child_bin = adw::Bin::builder()
.vexpand(true)
.hexpand(true)
.build(); .build();
content_box.append(&info_status_page); content_box.append(&installer_page_icon);
content_box.append(&installer_page_title);
content_box.append(&installer_page_subtitle);
content_box.append(&child_bin); content_box.append(&child_bin);
obj.connect_child_widget_notify(clone!( obj.connect_child_widget_notify(clone!(

336
src/language_page/mod.rs Normal file
View File

@ -0,0 +1,336 @@
use crate::installer_stack_page;
use crate::config;
use gtk::{prelude::*, glib as glib, Justification};
use adw::{prelude::*};
use glib::{clone, closure_local};
use std::{process::Command, env};
pub fn language_page(window: &adw::ApplicationWindow, main_carousel: &adw::Carousel) {
let language_page = installer_stack_page::InstallerStackPage::new();
language_page.set_page_title(t!("select_a_language"));
language_page.set_page_subtitle(t!("please_select_locale"));
language_page.set_page_icon("preferences-desktop-locale-symbolic");
language_page.set_back_visible(true);
language_page.set_next_visible(true);
language_page.set_back_sensitive(true);
language_page.set_next_sensitive(false);
let content_box = gtk::Box::builder()
.orientation(gtk::Orientation::Vertical)
.hexpand(true)
.vexpand(true)
.margin_start(15)
.margin_end(15)
.margin_top(15)
.margin_bottom(15)
.build();
let null_checkbutton = gtk::CheckButton::builder()
.label(t!("no_locale_selected"))
.build();
let language_selection_row_viewport =
gtk::ScrolledWindow::builder()
.vexpand(true)
.hexpand(true)
.build();
let language_selection_row_viewport_box = gtk::ListBox::builder().build();
language_selection_row_viewport_box.add_css_class("boxed-list");
language_selection_row_viewport
.set_child(Some(&language_selection_row_viewport_box));
let language_selection_row_viewport_listbox = gtk::ListBox::builder()
.selection_mode(gtk::SelectionMode::None)
.margin_top(15)
.margin_bottom(15)
.margin_start(15)
.margin_end(15)
.build();
language_selection_row_viewport_listbox.add_css_class("boxed-list");
let language_search_bar = gtk::SearchEntry::builder()
.hexpand(true)
.margin_top(15)
.margin_bottom(15)
.placeholder_text(t!("search_for_language"))
.search_delay(500)
.build();
let current_locale = match env::var_os("LANG") {
Some(v) => v.into_string().unwrap(),
None => panic!("$LANG is not set"),
};
let locale_list = ["ab_GE",
"aa_DJ",
"af_ZA",
"ak_GH",
"sq_AL",
"am_ET",
"ar_EG",
"an_ES",
"hy_AM",
"as_IN",
"ar_AE",
"az_AZ",
"bs_BA",
"eu_ES",
"be_BY",
"bn_BD",
"ar_BH",
"bi_VU",
"bs_BA",
"br_FR",
"bg_BG",
"my_MM",
"ca_ES",
"de_CH",
"ce_RU",
"zh_CN",
"cv_RU",
"kw_GB",
"es_CO",
"es_CR",
"hr_HR",
"cs_CZ",
"da_DK",
"dv_MV",
"nl_NL",
"dz_BT",
"en_US",
"en_GB",
"eo",
"et_EE",
"et_EE",
"fo_FO",
"hif_FJ",
"fi_FI",
"fr_FR",
"ff_SN",
"gl_ES",
"ka_GE",
"de_DE",
"el_GR",
"gu_IN",
"ht_HT",
"ha_NG",
"he_IL",
"hi_IN",
"hu_HU",
"ia_FR",
"id_ID",
"en_IE",
"ga_IE",
"ig_NG",
"ik_CA",
"is_IS",
"it_IT",
"iu_CA",
"ja_JP",
"kl_GL",
"kn_IN",
"ko_KR",
"kk_KZ",
"km_KH",
"rw_RW",
"ky_KG",
"ky_KG",
"ko_KR",
"ku_TR",
"lo_LA",
"lb_LU",
"lg_UG",
"li_NL",
"ln_CD",
"lo_LA",
"lt_LT",
"fr_LU",
"lv_LV",
"gv_GB",
"mk_MK",
"mg_MG",
"ms_MY",
"ml_IN",
"mt_MT",
"mi_NZ",
"mr_IN",
"mn_MN",
"ne_NP",
"en_NG",
"nb_NO",
"nn_NO",
"no_NO",
"nr_ZA",
"oc_FR",
"es_CU",
"om_ET",
"or_IN",
"os_RU",
"pa_IN",
"fa_IR",
"pl_PL",
"ps_AF",
"pt_BR",
"ro_RO",
"ru_RU",
"sa_IN",
"sc_IT",
"sd_IN",
"se_NO",
"sm_WS",
"en_SG",
"sr_RS",
"gd_GB",
"wo_SN",
"si_LK",
"sk_SK",
"sl_SI",
"so_SO",
"st_ZA",
"es_ES",
"sw_KE",
"ss_ZA",
"sv_SE",
"ta_IN",
"te_IN",
"tg_TJ",
"th_TH",
"ti_ER",
"bo_CN",
"tk_TM",
"tl_PH",
"tn_ZA",
"to_TO",
"tr_TR",
"ts_ZA",
"tt_RU",
"zh_TW",
"ug_CN",
"uk_UA",
"ur_PK",
"ve_ZA",
"vi_VN",
"wa_BE",
"cy_GB",
"wo_SN",
"fy_NL",
"xh_ZA",
"yi_US",
"yo_NG",
"zu_ZA",
"zu_ZA",
"pt_BR",
"pt_PT",];
let lang_data_buffer = gtk::TextBuffer::builder().build();
for locale in locale_list.iter() {
let locale = locale.to_string();
let locale_name_cli =
Command::new("/usr/lib/pika/pika-installer-gtk4/scripts/locale-name.py")
.arg(locale.clone())
.output()
.expect("failed to execute process");
let locale_name = String::from_utf8(locale_name_cli.stdout).unwrap();
let locale_clone = locale.clone();
let locale_checkbutton = gtk::CheckButton::builder()
.valign(gtk::Align::Center)
.can_focus(false)
.build();
let locale_row = adw::ActionRow::builder()
.activatable_widget(&locale_checkbutton)
.title(locale_name)
.subtitle(locale.clone())
.build();
locale_row.add_prefix(&locale_checkbutton);
locale_checkbutton.set_group(Some(&null_checkbutton));
language_selection_row_viewport_box.append(&locale_row);
locale_checkbutton.connect_toggled(clone!(
#[weak]
locale_checkbutton,
#[weak]
lang_data_buffer,
#[weak]
language_page,
move |_|
{
if locale_checkbutton.is_active() == true {
language_page.set_next_sensitive(true);
lang_data_buffer.set_text(&locale);
}
}
));
if current_locale.contains(&(locale_clone))
&& current_locale != "C.UTF-8"
&& current_locale != "C"
&& current_locale != "C.utf8"
&& current_locale != "POSIX"
{
locale_checkbutton.set_active(true);
}
}
// / content_box appends
//// add text and and entry to language page selections
content_box.append(&language_search_bar);
content_box.append(&language_selection_row_viewport);
let lang_data_buffer_clone = lang_data_buffer.clone();
language_search_bar.connect_search_changed(clone!(
#[weak]
language_search_bar,
#[weak]
language_selection_row_viewport_box,
move |_|
{
let mut counter = language_selection_row_viewport_box.first_child();
while let Some(row) = counter {
if row.widget_name() == "AdwActionRow" {
if !language_search_bar.text().is_empty() {
if row.property::<String>("subtitle").to_lowercase().contains(&language_search_bar.text().to_string().to_lowercase()) || row.property::<String>("title").to_lowercase().contains(&language_search_bar.text().to_string().to_lowercase()) {
row.set_property("visible", true);
language_search_bar.grab_focus();
} else {
row.set_property("visible", false);
}
} else {
row.set_property("visible", true);
}
}
counter = row.next_sibling();
}
}
));
language_page.set_child_widget(&content_box);
language_page.connect_closure(
"back-button-pressed",
false,
closure_local!(
#[weak]
main_carousel,
move |language_page: installer_stack_page::InstallerStackPage|
{
main_carousel.scroll_to(&main_carousel.nth_page(0), true)
}
)
);
language_page.connect_closure(
"next-button-pressed",
false,
closure_local!(
#[weak]
main_carousel,
move |language_page: installer_stack_page::InstallerStackPage|
{
main_carousel.scroll_to(&main_carousel.nth_page(2), true)
}
)
);
main_carousel.append(&language_page);
}

View File

@ -5,6 +5,8 @@ mod config;
mod build_ui; mod build_ui;
mod efi_error_page; mod efi_error_page;
mod installer_stack_page; mod installer_stack_page;
mod welcome_page;
mod language_page;
#[macro_use] #[macro_use]
extern crate rust_i18n; extern crate rust_i18n;

61
src/welcome_page/mod.rs Normal file
View File

@ -0,0 +1,61 @@
use crate::installer_stack_page;
use crate::config;
use gtk::{prelude::*, glib as glib, Justification};
use glib::clone;
pub fn welcome_page(window: &adw::ApplicationWindow, main_carousel: &adw::Carousel) {
let welcome_page = installer_stack_page::InstallerStackPage::new();
welcome_page.set_page_title(t!("welcome"));
welcome_page.set_page_subtitle(t!("welcome_to_pikaos"));
welcome_page.set_page_icon(config::DISTRO_ICON);
welcome_page.set_back_visible(false);
welcome_page.set_next_visible(false);
let content_box = gtk::Box::builder()
.orientation(gtk::Orientation::Vertical)
.margin_start(15)
.margin_end(15)
.margin_top(15)
.margin_bottom(15)
.valign(gtk::Align::Center)
.halign(gtk::Align::Center)
.vexpand(true)
.hexpand(true)
.build();
content_box.add_css_class("linked");
let live_media_button = gtk::Button::builder()
.icon_name("drive-optical")
.label(t!("use_pikaos_in_live_media"))
.build();
let install_media_button = gtk::Button::builder()
.icon_name("drive-harddisk")
.label(t!("install_distro_to_system"))
.build();
install_media_button.connect_clicked(
clone!(
#[weak]
main_carousel,
move |_|
main_carousel.scroll_to(&main_carousel.nth_page(1), true)
)
);
live_media_button.connect_clicked(
clone!(
#[weak]
window,
move |_|
window.close()
)
);
content_box.append(&install_media_button);
content_box.append(&live_media_button);
welcome_page.set_child_widget(&content_box);
main_carousel.append(&welcome_page);
}