chore: add English/Turkish changelog cross-links

This commit is contained in:
Erkan IŞIK
2026-06-25 01:33:51 +03:00
parent 7f94c8c0cc
commit 71e2ab3829
14 changed files with 694 additions and 120 deletions
+1 -1
View File
@@ -303,7 +303,7 @@ impl Default for GlobalState {
oem_password_changed: false,
selected_package_groups: Vec::new(),
display_manager: "sddm".to_string(),
autologin: true,
autologin: false,
desktop_environment: detect_desktop_environment(),
branding_icons: std::collections::HashMap::new(),
branding_pisi_dark: String::new(),
+28 -4
View File
@@ -1265,10 +1265,22 @@ impl Job for ConfigureDisplayManagerJob {
match dm.as_str() {
"sddm" => {
let conf = format!("{}/usr/lib/sddm/sddm.conf.d/sddm.conf", self.mount);
let session = match self.desktop_environment.as_str() {
"plasma" => "plasmax11.desktop",
"xfce" => "xfce.desktop",
"gnome" => "gnome.desktop",
"cinnamon" => "cinnamon.desktop",
"budgie" => "budgie-desktop.desktop",
"lxde" => "LXDE.desktop",
"lxqt" => "lxqt.desktop",
"mate" => "mate.desktop",
"lumina" => "lumina-desktop.desktop",
_ => "plasmax11.desktop",
};
let content = if self.autologin {
format!(
"[Autologin]\nUser={}\nSession=plasmax11.desktop\n\n[Theme]\nCurrent=pisilinux24\n",
self.username
"[Autologin]\nUser={}\nSession={}\n\n[Theme]\nCurrent=pisilinux24\n",
self.username, session
)
} else {
"[Autologin]\nUser=\nSession=\n\n[Theme]\nCurrent=pisilinux24\n".to_string()
@@ -1299,10 +1311,22 @@ impl Job for ConfigureDisplayManagerJob {
let dir = format!("{}/etc/gdm", self.mount);
let _ = tokio::fs::create_dir_all(&dir).await;
let conf = format!("{}/etc/gdm/custom.conf", self.mount);
let session = match self.desktop_environment.as_str() {
"plasma" => "plasmax11.desktop",
"xfce" => "xfce.desktop",
"gnome" => "gnome.desktop",
"cinnamon" => "cinnamon.desktop",
"budgie" => "budgie-desktop.desktop",
"lxde" => "LXDE.desktop",
"lxqt" => "lxqt.desktop",
"mate" => "mate.desktop",
"lumina" => "lumina-desktop.desktop",
_ => "gnome.desktop",
};
let content = if self.autologin {
format!(
"[daemon]\nAutomaticLoginEnable=true\nAutomaticLogin={}\n",
self.username
"[daemon]\nAutomaticLoginEnable=true\nAutomaticLogin={}\nDefaultSession={}\n",
self.username, session
)
} else {
"[daemon]\n".to_string()
+1 -2
View File
@@ -7,7 +7,7 @@ mod branding;
mod funct;
use installer::{GlobalState, InstallerStep, WelcomeStep};
use steps::{LocationStep, KeyboardStep, UsersStep, SummaryStep, ExecutionStep, FinishStep, PartitionStep, BootloaderStep, NetworkStep, DisplayManagerStep};
use steps::{LocationStep, KeyboardStep, UsersStep, SummaryStep, ExecutionStep, FinishStep, PartitionStep, BootloaderStep, NetworkStep};
use eframe::egui;
use rust_i18n::t;
@@ -231,7 +231,6 @@ impl Default for YaliApp {
Box::new(PartitionStep::default()),
Box::new(UsersStep::default()),
Box::new(BootloaderStep::default()),
Box::new(DisplayManagerStep::default()),
Box::new(SummaryStep),
Box::new(ExecutionStep::default()),
Box::new(FinishStep),
+57 -54
View File
@@ -2,6 +2,7 @@ use eframe::egui;
use rust_i18n::t;
use crate::installer::{GlobalState, InstallerStep};
use crate::ui::theme;
use crate::funct::{form_label, form_input_text, form_input_password};
#[derive(Default)]
pub struct BootloaderStep {
@@ -26,77 +27,79 @@ impl InstallerStep for BootloaderStep {
}
fn show(&mut self, ui: &mut egui::Ui, state: &mut GlobalState) {
ui.heading(t!("bootloader_title"));
ui.label(t!("bootloader_description"));
theme::section_heading(ui, &t!("bootloader_title"));
ui.label(
egui::RichText::new(t!("bootloader_description"))
.color(theme::c_text_dim())
.size(13.0),
);
ui.add_space(12.0);
egui::Grid::new("bootloader_grid")
.num_columns(2)
.spacing([12.0, 10.0])
// ─── Önyükleyici Formu ──────────────────────────────────
egui::Frame::group(ui.style())
.fill(theme::c_bg_widget())
.rounding(6.0)
.inner_margin(egui::Margin::symmetric(10.0, 10.0))
.show(ui, |ui| {
// Hedef aygıt
ui.label(t!("bootloader_device_label"));
ui.horizontal(|ui| {
let mut device_list: Vec<String> = state.available_disks.iter()
.map(|d| d.name.clone())
.collect();
if device_list.is_empty() {
device_list.push(state.bootloader_device.clone());
}
let current = if state.bootloader_device.is_empty() {
device_list[0].clone()
} else {
state.bootloader_device.clone()
};
theme::show_combo_box(ui, "boot_device_select", current.as_str(), ui.available_width(), |ui, w| {
for dev in &device_list {
theme::selectable_value(ui, &mut state.bootloader_device, dev.clone(), dev.as_str(), w);
ui.set_width(ui.available_width());
ui.vertical(|ui| {
ui.add_space(10.0);
// Hedef aygıt
form_label(ui, &t!("bootloader_device_label"));
ui.horizontal(|ui| {
let mut device_list: Vec<String> = state.available_disks.iter()
.map(|d| d.name.clone())
.collect();
if device_list.is_empty() {
device_list.push(state.bootloader_device.clone());
}
let current = if state.bootloader_device.is_empty() {
device_list[0].clone()
} else {
state.bootloader_device.clone()
};
theme::show_combo_box(ui, "boot_device_select", current.as_str(), ui.available_width(), |ui, w| {
for dev in &device_list {
theme::selectable_value(ui, &mut state.bootloader_device, dev.clone(), dev.as_str(), w);
}
});
});
ui.label(
egui::RichText::new(t!("bootloader_device_hint"))
.size(11.0)
.color(egui::Color32::from_rgb(120, 120, 140)),
.color(theme::c_text_dim()),
);
});
ui.end_row();
ui.add_space(6.0);
// Timeout
ui.label(t!("bootloader_timeout_label"));
ui.horizontal(|ui| {
ui.add(egui::Slider::new(&mut state.bootloader_timeout, 0..=60)
.text(t!("bootloader_timeout_suffix")));
});
ui.end_row();
// Timeout
form_label(ui, &t!("bootloader_timeout_label"));
ui.horizontal(|ui| {
ui.add(egui::Slider::new(&mut state.bootloader_timeout, 0..=60)
.text(t!("bootloader_timeout_suffix")));
});
ui.add_space(6.0);
// GRUB şifresi
ui.label(t!("bootloader_password_label"));
ui.horizontal(|ui| {
if self.show_password {
ui.text_edit_singleline(&mut state.bootloader_password);
} else {
ui.add(egui::TextEdit::singleline(&mut state.bootloader_password).password(true));
}
if ui.small_button(if self.show_password { "🙈" } else { "👁" }).clicked() {
self.show_password = !self.show_password;
}
if !state.bootloader_password.is_empty() {
ui.colored_label(egui::Color32::from_rgb(200, 180, 40), "⚠");
}
});
ui.end_row();
// GRUB şifresi
form_label(ui, &t!("bootloader_password_label"));
ui.horizontal(|ui| {
let show_pwd = &mut self.show_password;
form_input_password(ui, &mut state.bootloader_password, show_pwd);
});
ui.add_space(6.0);
// Kernel parametreleri
ui.label(t!("bootloader_kernel_label"));
ui.horizontal(|ui| {
ui.text_edit_singleline(&mut state.kernel_options);
// Kernel parametreleri
form_label(ui, &t!("bootloader_kernel_label"));
ui.horizontal(|ui| {
form_input_text(ui, &mut state.kernel_options);
});
ui.label(
egui::RichText::new(t!("bootloader_kernel_hint"))
.size(11.0)
.color(egui::Color32::from_rgb(120, 120, 140)),
.color(theme::c_text_dim()),
);
});
ui.end_row();
});
}
+1 -2
View File
@@ -7,7 +7,7 @@ pub mod partition;
pub mod bootloader;
pub mod network;
pub mod rescue;
pub mod display_manager;
//pub mod display_manager;
pub mod netinstall;
pub mod location;
@@ -20,5 +20,4 @@ pub use partition::PartitionStep;
pub use bootloader::BootloaderStep;
pub use network::NetworkStep;
pub use rescue::RescueStep;
pub use display_manager::DisplayManagerStep;
pub use location::LocationStep;
+150 -41
View File
@@ -6,16 +6,18 @@ use crate::funct::{ form_input_text, form_input_password, form_label, form_check
/// Kullanıcı adı, şifre, hostname ve yönetici (root) şifresi ayarları adımı.
pub struct UsersStep {
use_same_for_admin: bool,
autologin: bool,
show_password: bool,
show_password_confirm: bool,
show_root_password: bool, // <-- Eklendi
show_root_password_confirm: bool, // <-- Eklendi
show_root_password: bool,
show_root_password_confirm: bool,
}
impl Default for UsersStep {
fn default() -> Self {
Self {
use_same_for_admin: true,
autologin: false,
show_password: false,
show_password_confirm: false,
show_root_password: false,
@@ -30,16 +32,22 @@ impl Default for UsersStep {
/// - Boşlukları `-`'ye çevirir
/// - Geçersiz karakterleri temizler
fn derive_username(real_name: &str) -> String {
let mut name = real_name.to_lowercase();
name = name
let name = real_name
.replace('ş', "s")
.replace('Ş', "s")
.replace('ğ', "g")
.replace('Ğ', "g")
.replace('ı', "i")
.replace('İ', "i")
.replace('ö', "o")
.replace('Ö', "o")
.replace('ü', "u")
.replace('Ü', "u")
.replace('ç', "c")
.replace('Ç', "c")
.replace(' ', "-")
.replace('_', "-");
.replace('_', "-")
.to_lowercase();
let valid: String = name.chars().filter(|c| c.is_ascii_alphanumeric() || *c == '-' || *c == '_').collect();
let trimmed = valid.trim_matches('-').to_string();
if trimmed.is_empty() {
@@ -54,17 +62,44 @@ fn derive_username(real_name: &str) -> String {
/// Kullanıcı adının geçerliliğini kontrol eder.
/// Linux kuralları: küçük harf veya alt çizgi ile başlamalı,
/// en fazla 32 karakter, yalnızca [a-z0-9_-] içermeli.
fn is_valid_username(s: &str) -> bool {
if s.is_empty() || s.len() > 32 {
return false;
/// Ayrıca sistem kullanıcı adları yasaklıdır.
/// Hata varsa hata mesajını döndürür, yoksa None döndürür.
fn validate_username(s: &str) -> Option<String> {
if s.is_empty() {
return None;
}
if s.len() > 32 {
return Some(t!("username_too_long").to_string());
}
// Yasaklı sistem kullanıcı adları
let forbidden = [
"root", "daemon", "bin", "sys", "sync", "games", "man", "lp",
"mail", "news", "uucp", "proxy", "www-data", "backup", "list",
"irc", "gnats", "nobody", "systemd-timesync", "systemd-network",
"systemd-resolve", "systemd-bus-proxy", "messagebus", "sshd",
"ftp", "apache", "nginx", "mysql", "postgres", "docker",
];
if forbidden.contains(&s) {
return Some(t!("username_forbidden").to_string());
}
let mut chars = s.chars();
// İlk karakter küçük harf veya alt çizgi olmalı
match chars.next() {
Some(c) if c.is_ascii_lowercase() || c == '_' => {}
_ => return false,
_ => return Some(t!("username_invalid_start").to_string()),
}
chars.all(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || c == '_' || c == '-')
if !chars.all(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || c == '_' || c == '-') {
return Some(t!("username_invalid_chars").to_string());
}
None
}
/// Kullanıcı adının geçerliliğini kontrol eder (basit bool versiyonu).
fn is_valid_username(s: &str) -> bool {
validate_username(s).is_none()
}
/// Hostname kuralları: 1-63 karakter, yalnızca [a-zA-Z0-9-], tire ile başlayamaz/bitemez.
@@ -121,6 +156,9 @@ impl InstallerStep for UsersStep {
}
fn on_enter(&mut self, state: &mut GlobalState) {
// Autologin senkronizasyonu
self.autologin = state.autologin;
// Gerçek ad varsa ama kullanıcı adı yoksa türet
if !state.real_name.is_empty() && state.username.is_empty() {
state.username = derive_username(&state.real_name);
@@ -168,27 +206,54 @@ impl InstallerStep for UsersStep {
form_label(ui, &t!("real_name_label"));
{
let prev = state.real_name.clone();
form_input_text(ui, &mut state.real_name);
ui.horizontal(|ui| {
form_input_text(ui, &mut state.real_name);
if !state.real_name.is_empty() {
ui.add(
egui::Image::new(egui::include_image!("../../assets/icons/check.svg"))
.max_width(18.0).max_height(18.0)
.tint(theme::c_success())
);
}else{
ui.add(
egui::Image::new(egui::include_image!("../../assets/icons/fail-icon.svg"))
.max_width(18.0).max_height(18.0)
.tint(theme::c_error())
);
}
});
if state.real_name != prev && !state.real_name.is_empty() {
state.username = derive_username(&state.real_name);
}
}
if !state.real_name.is_empty() {
ui.colored_label(theme::c_success(), "✅");
} else {
ui.colored_label(theme::c_error(), "❌");
}
ui.add_space(6.0);
// Kullanıcı adı (otomatik türetilir, düzenlenebilir)
form_label(ui, &t!("username_label"));
form_input_text(ui, &mut state.username);
if !state.username.is_empty() {
if is_valid_username(&state.username) {
ui.colored_label(theme::c_success(), "✅");
} else {
ui.colored_label(theme::c_warning(), t!("username_invalid"));
ui.horizontal(|ui| {
form_input_text(ui, &mut state.username);
if !state.username.is_empty() {
if let Some(_err) = validate_username(&state.username) {
ui.add(
egui::Image::new(egui::include_image!("../../assets/icons/fail-icon.svg"))
.max_width(18.0).max_height(18.0)
.tint(theme::c_error())
);
} else {
ui.add(
egui::Image::new(egui::include_image!("../../assets/icons/check.svg"))
.max_width(18.0).max_height(18.0)
.tint(theme::c_success())
);
}
}
});
if let Some(err) = validate_username(&state.username) {
ui.colored_label(theme::c_error(), err);
}
ui.add_space(6.0);
@@ -221,27 +286,50 @@ impl InstallerStep for UsersStep {
form_label(ui, &t!("password_confirm_label"));
{
let show_pwd = &mut self.show_password_confirm;
form_input_password(ui, &mut state.password_confirm, show_pwd);
ui.horizontal(|ui| {
form_input_password(ui, &mut state.password_confirm, show_pwd);
if !state.password_confirm.is_empty() {
if state.password == state.password_confirm {
ui.add(
egui::Image::new(egui::include_image!("../../assets/icons/check.svg"))
.max_width(18.0).max_height(18.0)
.tint(theme::c_success())
);
} else {
ui.add(
egui::Image::new(egui::include_image!("../../assets/icons/fail-icon.svg"))
.max_width(18.0).max_height(18.0)
.tint(theme::c_error())
);
}
}
});
}
if !state.password_confirm.is_empty() {
if state.password == state.password_confirm {
ui.colored_label(theme::c_success(), "✅");
} else {
ui.colored_label(theme::c_warning(), t!("passwords_no_match"));
}
if !state.password_confirm.is_empty() && state.password != state.password_confirm {
ui.colored_label(theme::c_warning(), t!("passwords_no_match"));
}
ui.add_space(6.0);
// Hostname
form_label(ui, &t!("hostname_label"));
form_input_text(ui, &mut state.hostname);
if !state.hostname.is_empty() {
if is_valid_hostname(&state.hostname) {
ui.colored_label(theme::c_success(), "✅");
} else {
ui.colored_label(theme::c_warning(), t!("hostname_invalid"));
ui.horizontal(|ui| {
form_input_text(ui, &mut state.hostname);
if !state.hostname.is_empty() {
if is_valid_hostname(&state.hostname) {
ui.add(
egui::Image::new(egui::include_image!("../../assets/icons/check.svg"))
.max_width(18.0).max_height(18.0)
.tint(theme::c_success())
);
} else {
ui.add(
egui::Image::new(egui::include_image!("../../assets/icons/fail-icon.svg"))
.max_width(18.0).max_height(18.0)
.tint(theme::c_error())
);
}
}
}
});
});
ui.add_space(10.0);
@@ -250,9 +338,13 @@ impl InstallerStep for UsersStep {
ui.add_space(14.0);
// ─── Otomatik Oturum Açma ───────────────────────────────────────
form_checkbox(ui, &mut self.autologin, &t!("display_manager_autologin"));
ui.add_space(8.0);
// ─── Yönetici (root) Ayarları ─────────────────────────────────────
form_checkbox(ui, &mut self.use_same_for_admin, &t!("use_same_for_admin"));
if self.use_same_for_admin {
state.root_password = state.password.clone();
state.root_password_confirm = state.password_confirm.clone();
@@ -281,16 +373,33 @@ impl InstallerStep for UsersStep {
// DÜZELTME: 3. parametre olarak show_root_password_confirm eklendi
let show_root_pwd_conf = &mut self.show_root_password_confirm;
form_input_password(ui, &mut state.root_password_confirm, show_root_pwd_conf);
ui.horizontal(|ui| {
form_input_password(ui, &mut state.root_password_confirm, show_root_pwd_conf);
if !state.root_password_confirm.is_empty() {
if state.root_password == state.root_password_confirm {
ui.add(
egui::Image::new(egui::include_image!("../../assets/icons/check.svg"))
.max_width(18.0).max_height(18.0)
.tint(theme::c_success())
);
} else {
ui.add(
egui::Image::new(egui::include_image!("../../assets/icons/fail-icon.svg"))
.max_width(18.0).max_height(18.0)
.tint(theme::c_error())
);
}
}
});
if state.root_password == state.root_password_confirm {
ui.colored_label(theme::c_success(), "✅");
} else {
if !state.root_password_confirm.is_empty() && state.root_password != state.root_password_confirm {
ui.colored_label(theme::c_error(), t!("passwords_no_match"));
}
});
}
// Autologin değerini state'e kaydet
state.autologin = self.autologin;
}
fn is_complete(&self, state: &GlobalState) -> bool {
+9 -8
View File
@@ -60,28 +60,29 @@ pub fn set_theme_mode(is_dark: bool) {
BG_PANEL.store(0x1A1A1E, Ordering::Relaxed);
BG_WIDGET.store(0x242428, Ordering::Relaxed);
BORDER.store(0x323238, Ordering::Relaxed);
TEXT.store(0xF3F3F5, Ordering::Relaxed);
TEXT_DIM.store(0x9E9EAF, Ordering::Relaxed);
TEXT.store(0xF3F3F5, Ordering::Relaxed); // #F3F3F5
TEXT_DIM.store(0x9E9EAF, Ordering::Relaxed); // #9E9EAF
SIDEBAR.store(0x0B0B0D, Ordering::Relaxed);
SIDEBAR_TEXT.store(0xffffff, Ordering::Relaxed);
KEYBOARD_BG.store(0x000000, Ordering::Relaxed);
BG_ROOT.store(0x1A1A1E, Ordering::Relaxed);
} else {
BG_FOOTER.store(0xf7f7f7, Ordering::Relaxed);
BG_DARK.store(0xf7f7f7, Ordering::Relaxed);
SIDEBAR.store(0x292f34, Ordering::Relaxed);
TEXT.store(0x000000, Ordering::Relaxed);
TEXT_DIM.store(0x000000, Ordering::Relaxed);
TEXT.store(0x000000, Ordering::Relaxed); // #000000
TEXT_DIM.store(0x000000, Ordering::Relaxed); // #000000
SIDEBAR_TEXT.store(0xffffff, Ordering::Relaxed);
KEYBOARD_BG.store(0xffffff, Ordering::Relaxed);
BG_ROOT.store(0xf7f7f7, Ordering::Relaxed);
BG_DARK.store(0xF0F0F5, Ordering::Relaxed);
//BG_DARK.store(0xF0F0F5, Ordering::Relaxed);
BG_PANEL.store(0xFFFFFF, Ordering::Relaxed);
BG_WIDGET.store(0xE8E8EE, Ordering::Relaxed);
BORDER.store(0xD0D0DA, Ordering::Relaxed);
TEXT.store(0x20202A, Ordering::Relaxed);
TEXT_DIM.store(0x60606A, Ordering::Relaxed);
SIDEBAR.store(0xE4E4EA, Ordering::Relaxed);
//TEXT.store(0x20202A, Ordering::Relaxed); // #20202A
//TEXT_DIM.store(0x60606A, Ordering::Relaxed); // #60606A
//SIDEBAR.store(0xE4E4EA, Ordering::Relaxed);
}
}