mirror of
https://gitlab.com/erkanisik/yali-rs.git
synced 2026-07-30 18:59:02 +00:00
Merge branch 'main' into 'main'
feat: form input styling, root password toggle, partition UI fixes See merge request ayhanyalcinsoy/yali-rs!7
This commit is contained in:
@@ -1,5 +1,39 @@
|
||||
# Changelog
|
||||
|
||||
## [4.0.2] — 2026-06-21
|
||||
|
||||
### Changed
|
||||
- Sürgü maksimum değeri artık diskteki kullanılabilir alan kadar (diğer bölümler hariç)
|
||||
- Düzenleme modunda seçili bölümün kapasitesi sürgü aralığına dahil edildi
|
||||
- `form_input_text` boyut alanı doğrudan `add_size_str`'e bağlandı, yanında formatlı MB gösterimi eklendi
|
||||
- Boyut etiketi artık `"123 MB"` yerine `"123.456 MB"` formatında (parse edilebilen değerlerde)
|
||||
|
||||
### Fixed
|
||||
- Boyut input alanına yazılan değer `add_size_str`'e geri yazılmıyordu — text edit salt okunur kalıyordu
|
||||
|
||||
---
|
||||
|
||||
## [4.0.1] — 2026-06-19
|
||||
|
||||
### Added
|
||||
- `c_root_bg()` tema fonksiyonu
|
||||
- `show_root_password`, `show_root_password_confirm` alanları (`UsersStep`)
|
||||
- `form_input_text` / `form_input_password`'a `Frame` sarmalı ve `.frame(false)`
|
||||
|
||||
### Changed
|
||||
- `form_input_text`: Frame içine alındı, stroke/fill/rounding eklendi, yükseklik 32→10
|
||||
- `form_input_password`: SVG göz ikonları (emoji yerine), Frame sarmalı, `override_text_color`
|
||||
- Disk grid seçim renkleri `theme::c_*()` → sabit `(237,237,224,1)`
|
||||
- Disk listesi header ve sütun başlıkları: `Align::Center` → `Align::LEFT`, `vertical_centered` kaldırıldı
|
||||
- Root şifre alanları raw `TextEdit` → `form_input_password` (göz ikonu + frame ile)
|
||||
- Kullanıcı formu Frame rengi `theme::c_bg_widget()` → `(240,243,198)`
|
||||
- Manuel disk listesinde marka/model etiketi sıralaması değiştirildi
|
||||
|
||||
### Fixed
|
||||
- `users.rs:154` — `Color32` import hatası (missing `egui::` prefix)
|
||||
|
||||
---
|
||||
|
||||
## [4.0.0] — 2026-06-18
|
||||
|
||||
### Added
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 122.88 122.88"><defs><style>.cls-1{fill:#ff4141;fill-rule:evenodd;}</style></defs><title>cross</title><path class="cls-1" d="M6,6H6a20.53,20.53,0,0,1,29,0l26.5,26.49L87.93,6a20.54,20.54,0,0,1,29,0h0a20.53,20.53,0,0,1,0,29L90.41,61.44,116.9,87.93a20.54,20.54,0,0,1,0,29h0a20.54,20.54,0,0,1-29,0L61.44,90.41,35,116.9a20.54,20.54,0,0,1-29,0H6a20.54,20.54,0,0,1,0-29L32.47,61.44,6,34.94A20.53,20.53,0,0,1,6,6Z"/></svg>
|
||||
|
After Width: | Height: | Size: 500 B |
@@ -0,0 +1 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 122.88 111.54"><defs><style>.cls-1{fill:#cf1f25;}.cls-2{fill:#fec901;fill-rule:evenodd;}.cls-3{fill:#010101;}</style></defs><title>warning</title><path class="cls-1" d="M2.35,84.42,45.28,10.2l.17-.27h0A23,23,0,0,1,52.5,2.69,17,17,0,0,1,61.57,0a16.7,16.7,0,0,1,9.11,2.69,22.79,22.79,0,0,1,7,7.26q.19.32.36.63l42.23,73.34.24.44h0a22.48,22.48,0,0,1,2.37,10.19,17.63,17.63,0,0,1-2.17,8.35,15.94,15.94,0,0,1-6.93,6.6c-.19.1-.39.18-.58.26a21.19,21.19,0,0,1-9.11,1.75v0H17.61c-.22,0-.44,0-.65,0a18.07,18.07,0,0,1-6.2-1.15A16.42,16.42,0,0,1,3,104.24a17.53,17.53,0,0,1-3-9.57,23,23,0,0,1,1.57-8.74,7.66,7.66,0,0,1,.77-1.51Z"/><path class="cls-2" d="M9,88.75,52.12,14.16c5.24-8.25,13.54-8.46,18.87,0l42.43,73.69c3.39,6.81,1.71,16-9.33,15.77H17.61C10.35,103.8,5.67,97.43,9,88.75Z"/><path class="cls-3" d="M57.57,83.78A5.53,5.53,0,0,1,61,82.2a5.6,5.6,0,0,1,2.4.36,5.7,5.7,0,0,1,2,1.3,5.56,5.56,0,0,1,1.54,5,6.23,6.23,0,0,1-.42,1.35,5.57,5.57,0,0,1-5.22,3.26,5.72,5.72,0,0,1-2.27-.53A5.51,5.51,0,0,1,56.28,90a5.18,5.18,0,0,1-.36-1.27,5.83,5.83,0,0,1-.06-1.31h0a6.53,6.53,0,0,1,.57-2,4.7,4.7,0,0,1,1.14-1.56Zm8.15-10.24c-.19,4.79-8.31,4.8-8.49,0-.82-8.21-2.92-29.34-2.86-37.05.07-2.38,2-3.79,4.56-4.33a12.83,12.83,0,0,1,5,0c2.61.56,4.65,2,4.65,4.44v.24L65.72,73.54Z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
@@ -268,6 +268,9 @@ mp_select_hint = "Select…"
|
||||
mp_add_btn = "✓ Add"
|
||||
mp_size_hint = "Size (MB, 0=remaining):"
|
||||
mp_delete_confirm_yes = "✓ Yes, Delete"
|
||||
mp_new_partition = "New Partition"
|
||||
mp_edit_partition = "Edit"
|
||||
mp_save = "✓ Save"
|
||||
plan_root_suffix = " (root)"
|
||||
disk_min_required = " ↳ %{err} (min. %{n} GB required)"
|
||||
|
||||
|
||||
@@ -240,6 +240,9 @@ mp_select_hint = "Seç…"
|
||||
mp_add_btn = "✓ Ekle"
|
||||
mp_size_hint = "Boyut (MB, 0=kalan):"
|
||||
mp_delete_confirm_yes = "✓ Evet, Sil"
|
||||
mp_new_partition = "Yeni Bölüm"
|
||||
mp_edit_partition = "Düzenle"
|
||||
mp_save = "✓ Kaydet"
|
||||
plan_root_suffix = " (kök)"
|
||||
disk_min_required = " ↳ %{err} (min. %{n} GB gerekli)"
|
||||
|
||||
|
||||
+61
-21
@@ -18,18 +18,27 @@ pub fn form_input_text(
|
||||
)-> eframe::egui::Response {
|
||||
|
||||
let width_percent = 0.90; // Mevcut genişliğin %90'ı
|
||||
let height = 32.0; // Standart yükseklik
|
||||
let height = 10.0; // Standart yükseklik
|
||||
let hesaplanan_genislik = ui.available_width() * width_percent;
|
||||
let boyut = eframe::egui::vec2(hesaplanan_genislik, height);
|
||||
|
||||
ui.spacing_mut().button_padding = eframe::egui::vec2(10.0, 10.0);
|
||||
egui::Frame::none()
|
||||
.fill(egui::Color32::from_rgb(255, 255, 255))
|
||||
.stroke(egui::Stroke::new(1.0, egui::Color32::from_gray(200)))
|
||||
.rounding(4.0)
|
||||
.inner_margin(eframe::egui::Margin::symmetric(2.0, 2.0))
|
||||
.show(ui, |ui| {
|
||||
ui.add_sized(
|
||||
boyut,
|
||||
eframe::egui::TextEdit::singleline(text)
|
||||
.vertical_align(eframe::egui::Align::Center)
|
||||
.frame(false),
|
||||
)
|
||||
}).inner
|
||||
}
|
||||
|
||||
|
||||
pub fn form_input_password(
|
||||
ui: &mut eframe::egui::Ui,
|
||||
text: &mut String,
|
||||
@@ -38,28 +47,59 @@ pub fn form_input_password(
|
||||
let width_percent = 0.90;
|
||||
let height = 32.0;
|
||||
let toplam_genislik = ui.available_width() * width_percent;
|
||||
let dugme_genislik = 40.0;
|
||||
let alan_genislik = toplam_genislik - dugme_genislik - 4.0;
|
||||
let boyut = eframe::egui::vec2(alan_genislik, height);
|
||||
|
||||
let buton_genislik = 32.0;
|
||||
let alan_genislik = toplam_genislik - buton_genislik - 4.0;
|
||||
|
||||
ui.spacing_mut().button_padding = eframe::egui::vec2(10.0, 10.0);
|
||||
let mut response: Option<eframe::egui::Response> = None;
|
||||
|
||||
ui.horizontal(|ui| {
|
||||
let r = ui.add_sized(
|
||||
boyut,
|
||||
eframe::egui::TextEdit::singleline(text)
|
||||
.password(!*show_password)
|
||||
.vertical_align(eframe::egui::Align::Center),
|
||||
);
|
||||
let göz = if *show_password { "🙈" } else { "👁" };
|
||||
if ui.add(
|
||||
eframe::egui::Button::new(göz)
|
||||
.min_size(eframe::egui::vec2(dugme_genislik, height))
|
||||
).clicked() {
|
||||
*show_password = !*show_password;
|
||||
}
|
||||
r
|
||||
}).inner
|
||||
ui.visuals_mut().override_text_color = Some(eframe::egui::Color32::from_rgb(30, 30, 30));
|
||||
|
||||
// SVG içeriklerini string olarak tanımlıyoruz
|
||||
let goz_acik_svg = r#"<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M2.036 12.322a1.012 1.012 0 0 1 0-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178Z" /><path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" /></svg>"#;
|
||||
let goz_kapali_svg = r#"<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M3.98 8.223A10.477 10.477 0 0 0 1.934 12C3.226 16.338 7.244 19.5 12 19.5c.993 0 1.953-.138 2.863-.395M6.228 6.228A10.451 10.451 0 0 1 12 4.5c4.756 0 8.773 3.162 10.065 7.498a10.522 10.522 0 0 1-4.293 5.774M6.228 6.228 3 3m3.228 3.228 3.65 3.65m7.894 7.894L21 21m-3.228-3.228-3.65-3.65m0 0a3 3 0 1 0-4.243-4.243m4.242 4.242L9.88 9.88" /></svg>"#;
|
||||
|
||||
eframe::egui::Frame::none()
|
||||
.fill(eframe::egui::Color32::WHITE)
|
||||
.stroke(eframe::egui::Stroke::new(1.0, eframe::egui::Color32::from_rgb(200, 200, 200)))
|
||||
.rounding(6.0)
|
||||
.inner_margin(eframe::egui::Margin::symmetric(2.0, 2.0))
|
||||
.show(ui, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
// 1. Şifre Metin Alanı
|
||||
let r = ui.add_sized(
|
||||
eframe::egui::vec2(alan_genislik, height),
|
||||
eframe::egui::TextEdit::singleline(text)
|
||||
.password(!*show_password)
|
||||
.frame(false)
|
||||
);
|
||||
response = Some(r);
|
||||
|
||||
// Duruma göre ilgili SVG string'ini seçip byte dizisine (&[u8]) çeviriyoruz
|
||||
let (uri, svg_bytes) = if *show_password {
|
||||
("bytes://goz_acik.svg", goz_acik_svg.as_bytes())
|
||||
} else {
|
||||
("bytes://goz_kapali.svg", goz_kapali_svg.as_bytes())
|
||||
};
|
||||
|
||||
// Image::from_bytes kullanarak imajı güvenli bir şekilde yüklüyoruz
|
||||
let svg_gosterici = eframe::egui::Image::from_bytes(uri, svg_bytes)
|
||||
.tint(eframe::egui::Color32::from_rgb(120, 120, 120))
|
||||
.max_width(18.0)
|
||||
.max_height(18.0);
|
||||
|
||||
// 2. SVG İkonlu Buton
|
||||
let btn = eframe::egui::Button::image(svg_gosterici)
|
||||
.frame(false)
|
||||
.min_size(eframe::egui::vec2(buton_genislik, height));
|
||||
|
||||
if ui.add(btn).on_hover_cursor(eframe::egui::CursorIcon::PointingHand).clicked() {
|
||||
*show_password = !*show_password;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
response.expect("Metin alanı yüklenemedi")
|
||||
}
|
||||
|
||||
pub fn form_label(ui: &mut eframe::egui::Ui, text: &str) {
|
||||
|
||||
+23
-7
@@ -449,15 +449,31 @@ impl InstallerStep for WelcomeStep {
|
||||
egui::Grid::new("checks_grid")
|
||||
.num_columns(3)
|
||||
.spacing([10.0, 6.0])
|
||||
.striped(true)
|
||||
.show(ui, |ui| {
|
||||
for check in &self.checks {
|
||||
let (icon, color) = match check.status {
|
||||
CheckStatus::Pass => ("✅", theme::c_success()),
|
||||
CheckStatus::Warn => ("⚠️", theme::c_warning()),
|
||||
CheckStatus::Fail => ("❌", theme::c_error()),
|
||||
};
|
||||
ui.colored_label(color, icon);
|
||||
match check.status {
|
||||
CheckStatus::Pass => {
|
||||
ui.add(
|
||||
egui::Image::new(egui::include_image!("../assets/icons/check.svg"))
|
||||
.max_width(18.0).max_height(18.0)
|
||||
.tint(theme::c_success())
|
||||
);
|
||||
}
|
||||
CheckStatus::Warn => {
|
||||
ui.add(
|
||||
egui::Image::new(egui::include_image!("../assets/icons/warning-icon.svg"))
|
||||
.max_width(18.0).max_height(18.0)
|
||||
.tint(theme::c_warning())
|
||||
);
|
||||
}
|
||||
CheckStatus::Fail => {
|
||||
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.label(egui::RichText::new(&check.name).strong().color(theme::c_text()));
|
||||
ui.label(
|
||||
egui::RichText::new(&check.message)
|
||||
|
||||
+350
-146
@@ -3,6 +3,7 @@
|
||||
use eframe::egui;
|
||||
use rust_i18n::t;
|
||||
use crate::ui::theme;
|
||||
use crate::funct::{form_label, form_input_text};
|
||||
// sysinfo::Disks mount point başına bir kayıt döndürür (partition'lar),
|
||||
// ham disk listesi için lsblk kullanıyoruz.
|
||||
|
||||
@@ -220,6 +221,12 @@ const COMMON_MOUNTPOINTS: &[&str] = &["/", "/boot", "/boot/efi", "/home", "/var"
|
||||
struct ManualState {
|
||||
/// "Bölüm Ekle" diyaloğu açık mı?
|
||||
adding: bool,
|
||||
/// "Bölüm Düzenle" diyaloğı açık mı?
|
||||
editing: bool,
|
||||
/// Düzenlenecek bölüm indeksi
|
||||
edit_idx: Option<usize>,
|
||||
/// Seçili satır indeksi
|
||||
selected_idx: Option<usize>,
|
||||
/// Diyalog: seçili dosya sistemi
|
||||
add_fstype: usize, // FsType listesindeki indeks
|
||||
/// Diyalog: boyut alanı (MB, metin girişi)
|
||||
@@ -363,8 +370,17 @@ impl InstallerStep for PartitionStep {
|
||||
|
||||
// ── Mod seçimi ─────────────────────────────────────────
|
||||
ui.horizontal(|ui| {
|
||||
ui.selectable_value(&mut state.erase_disk, true, t!("erase_disk_label"));
|
||||
ui.selectable_value(&mut state.erase_disk, false, t!("manual_partition_label"));
|
||||
if state.erase_disk {
|
||||
let _ = theme::primary_button(ui, &t!("erase_disk_label"));
|
||||
if theme::secondary_button(ui, &t!("manual_partition_label")).clicked() {
|
||||
state.erase_disk = false;
|
||||
}
|
||||
} else {
|
||||
if theme::secondary_button(ui, &t!("erase_disk_label")).clicked() {
|
||||
state.erase_disk = true;
|
||||
}
|
||||
let _ = theme::primary_button(ui, &t!("manual_partition_label"));
|
||||
}
|
||||
});
|
||||
ui.add_space(10.0);
|
||||
|
||||
@@ -415,13 +431,11 @@ impl PartitionStep {
|
||||
// arka plan
|
||||
egui::Frame::none()
|
||||
.fill(if selected {
|
||||
crate::ui::theme::c_accent_dim()
|
||||
egui::Color32::from_rgba_unmultiplied(237, 237, 224, 1)
|
||||
} else if response.hovered() {
|
||||
egui::Color32::from_rgba_unmultiplied(60, 60, 80, 180)
|
||||
} else if too_small {
|
||||
egui::Color32::from_rgba_unmultiplied(60, 30, 30, 180)
|
||||
} else {
|
||||
crate::ui::theme::c_bg_widget()
|
||||
egui::Color32::from_rgba_unmultiplied(237, 237, 224, 1)
|
||||
})
|
||||
.stroke(egui::Stroke::new(
|
||||
if selected { 2.0 } else { 1.0 },
|
||||
@@ -509,15 +523,15 @@ impl PartitionStep {
|
||||
egui::vec2(tam_genislik * col_widths[j], 30.0),
|
||||
egui::Sense::hover(),
|
||||
);
|
||||
let child_ui = &mut ui.child_ui(rect, egui::Layout::top_down(egui::Align::Center));
|
||||
let child_ui = &mut ui.child_ui(rect, egui::Layout::top_down(egui::Align::LEFT));
|
||||
egui::Frame::none()
|
||||
.fill(header_color)
|
||||
.stroke(egui::Stroke::new(1.0, header_color))
|
||||
.inner_margin(egui::Margin::symmetric(8.0, 4.0))
|
||||
.show(child_ui, |ui| {
|
||||
ui.vertical_centered(|ui| {
|
||||
ui.label(egui::RichText::new(h).strong().color(header_text).size(13.0));
|
||||
});
|
||||
ui.label(egui::RichText::new(h)
|
||||
.strong()
|
||||
.color(header_text)
|
||||
.size(13.0));
|
||||
});
|
||||
}
|
||||
ui.end_row();
|
||||
@@ -628,7 +642,6 @@ impl PartitionStep {
|
||||
|
||||
impl PartitionStep {
|
||||
fn show_manual_mode(&mut self, ui: &mut egui::Ui, state: &mut GlobalState) {
|
||||
let accent = crate::ui::theme::c_accent();
|
||||
let kart_genislik = 180.0;
|
||||
let kart_yukseklik = 160.0;
|
||||
|
||||
@@ -653,11 +666,11 @@ impl PartitionStep {
|
||||
|
||||
egui::Frame::none()
|
||||
.fill(if selected {
|
||||
crate::ui::theme::c_accent_dim()
|
||||
egui::Color32::from_rgba_unmultiplied(237, 237, 224, 1)
|
||||
} else if response.hovered() {
|
||||
egui::Color32::from_rgba_unmultiplied(60, 60, 80, 180)
|
||||
} else {
|
||||
crate::ui::theme::c_bg_widget()
|
||||
egui::Color32::from_rgba_unmultiplied(237, 237, 224, 1)
|
||||
})
|
||||
.stroke(egui::Stroke::new(
|
||||
if selected { 2.0 } else { 1.0 },
|
||||
@@ -680,17 +693,20 @@ impl PartitionStep {
|
||||
} else {
|
||||
&disk.vendor
|
||||
};
|
||||
|
||||
ui.label(
|
||||
egui::RichText::new(marka)
|
||||
.size(11.0)
|
||||
.color(crate::ui::theme::c_text_dim()),
|
||||
);
|
||||
|
||||
ui.label(
|
||||
egui::RichText::new(format!("{} GB", disk.size_gb))
|
||||
.size(14.0)
|
||||
.strong()
|
||||
.color(crate::ui::theme::c_text()),
|
||||
);
|
||||
ui.label(
|
||||
egui::RichText::new(marka)
|
||||
.size(11.0)
|
||||
.color(crate::ui::theme::c_text_dim()),
|
||||
);
|
||||
|
||||
});
|
||||
|
||||
if response.clicked() {
|
||||
@@ -715,12 +731,17 @@ impl PartitionStep {
|
||||
return;
|
||||
}
|
||||
};
|
||||
let disk_size_gb = state.available_disks.iter()
|
||||
.find(|d| d.name == disk)
|
||||
.map(|d| d.size_gb)
|
||||
.unwrap_or(256);
|
||||
let max_mb = (disk_size_gb as f64) * 1024.0;
|
||||
|
||||
// ── Mevcut bölüm listesi tablosu ───────────────────────
|
||||
ui.label(egui::RichText::new(t!("mp_plan_title")).strong().color(crate::ui::theme::c_text()));
|
||||
ui.add_space(6.0);
|
||||
|
||||
let mut delete_idx: Option<usize> = None;
|
||||
let delete_idx: Option<usize> = None;
|
||||
|
||||
let col_widths = [0.28, 0.12, 0.18, 0.27, 0.15];
|
||||
let tam_genislik = ui.available_width();
|
||||
@@ -735,12 +756,11 @@ impl PartitionStep {
|
||||
|
||||
grid.show(ui, |ui| {
|
||||
// ── Başlık satırı ─────────────────────────────────
|
||||
let headers: [String; 5] = [
|
||||
let headers: [String; 4] = [
|
||||
t!("mp_device").to_string(),
|
||||
t!("mp_size").to_string(),
|
||||
t!("mp_fstype").to_string(),
|
||||
t!("mp_mountpoint").to_string(),
|
||||
t!("mp_action").to_string(),
|
||||
t!("mp_mountpoint").to_string(),
|
||||
];
|
||||
for (j, h) in headers.into_iter().enumerate() {
|
||||
let (rect, _) = ui.allocate_exact_size(
|
||||
@@ -753,16 +773,17 @@ impl PartitionStep {
|
||||
.stroke(egui::Stroke::new(1.0, header_color))
|
||||
.inner_margin(egui::Margin::symmetric(8.0, 4.0))
|
||||
.show(child_ui, |ui| {
|
||||
ui.vertical_centered(|ui| {
|
||||
ui.label(egui::RichText::new(h).strong().color(header_text).size(13.0));
|
||||
});
|
||||
ui.label(egui::RichText::new(h).strong().color(header_text).size(13.0));
|
||||
});
|
||||
}
|
||||
ui.end_row();
|
||||
|
||||
// ── Veri satırları ────────────────────────────────
|
||||
for (row_idx, part) in state.custom_partitions.iter().enumerate() {
|
||||
let row_bg = if row_idx % 2 == 0 {
|
||||
let is_selected = self.manual.selected_idx == Some(row_idx);
|
||||
let row_bg = if is_selected {
|
||||
egui::Color32::from_rgba_unmultiplied(80, 100, 180, 80)
|
||||
} else if row_idx % 2 == 0 {
|
||||
egui::Color32::from_rgba_unmultiplied(60, 60, 80, 60)
|
||||
} else {
|
||||
egui::Color32::TRANSPARENT
|
||||
@@ -790,22 +811,32 @@ impl PartitionStep {
|
||||
];
|
||||
|
||||
for (j, (deger, is_action)) in hucreler.iter().enumerate() {
|
||||
let (rect, _response) = ui.allocate_exact_size(
|
||||
let sense = if *is_action {
|
||||
egui::Sense::click()
|
||||
} else {
|
||||
egui::Sense::click()
|
||||
};
|
||||
let (rect, response) = ui.allocate_exact_size(
|
||||
egui::vec2(tam_genislik * col_widths[j], 34.0),
|
||||
egui::Sense::click(),
|
||||
sense,
|
||||
);
|
||||
|
||||
if !*is_action {
|
||||
if response.clicked() {
|
||||
self.manual.selected_idx = Some(row_idx);
|
||||
}
|
||||
response.on_hover_cursor(egui::CursorIcon::PointingHand);
|
||||
}
|
||||
|
||||
let child_ui = &mut ui.child_ui(rect, egui::Layout::top_down(egui::Align::Center));
|
||||
|
||||
if *is_action {
|
||||
egui::Frame::none()
|
||||
.fill(row_bg)
|
||||
.stroke(egui::Stroke::new(0.0, egui::Color32::TRANSPARENT))
|
||||
.fill(egui::Color32::TRANSPARENT)
|
||||
.inner_margin(egui::Margin::symmetric(8.0, 4.0))
|
||||
.show(child_ui, |ui| {
|
||||
ui.vertical_centered(|ui| {
|
||||
if ui.small_button("🗑").on_hover_text(t!("mp_delete")).clicked() {
|
||||
delete_idx = Some(row_idx);
|
||||
}
|
||||
ui.label(egui::RichText::new(deger).size(13.0).color(crate::ui::theme::c_text()));
|
||||
});
|
||||
});
|
||||
} else {
|
||||
@@ -827,6 +858,16 @@ impl PartitionStep {
|
||||
}
|
||||
});
|
||||
|
||||
// ── Bölümleme Planı (manuel) ──────────────────────────
|
||||
if !state.custom_partitions.is_empty() {
|
||||
ui.add_space(12.0);
|
||||
ui.separator();
|
||||
ui.add_space(8.0);
|
||||
ui.label(egui::RichText::new(t!("partition_plan_title")).strong().color(crate::ui::theme::c_text()));
|
||||
ui.add_space(6.0);
|
||||
manual_partition_bar(ui, &state.custom_partitions);
|
||||
}
|
||||
|
||||
// Silme onayı
|
||||
if let Some(idx) = delete_idx {
|
||||
self.manual.delete_idx = Some(idx);
|
||||
@@ -843,13 +884,14 @@ impl PartitionStep {
|
||||
ui.label(t!("mp_confirm_delete", dev = dev));
|
||||
ui.add_space(8.0);
|
||||
ui.horizontal(|ui| {
|
||||
if ui.button(t!("mp_delete_confirm_yes")).clicked() {
|
||||
if theme::danger_button(ui, &t!("mp_delete_confirm_yes")).clicked() {
|
||||
if idx < state.custom_partitions.len() {
|
||||
state.custom_partitions.remove(idx);
|
||||
}
|
||||
self.manual.delete_idx = None;
|
||||
self.manual.selected_idx = None;
|
||||
}
|
||||
if ui.button(t!("cancel")).clicked() {
|
||||
if theme::secondary_button(ui, &t!("cancel")).clicked() {
|
||||
self.manual.delete_idx = None;
|
||||
}
|
||||
});
|
||||
@@ -858,126 +900,199 @@ impl PartitionStep {
|
||||
|
||||
ui.add_space(8.0);
|
||||
|
||||
// ── "Bölüm Ekle" butonu ────────────────────────────────
|
||||
let btn = egui::Button::new(format!("➕ {}", t!("mp_add")))
|
||||
.fill(accent.gamma_multiply(0.15));
|
||||
if ui.add(btn).clicked() {
|
||||
self.manual.adding = true;
|
||||
let next_num = state.custom_partitions.len() + 1;
|
||||
self.manual.add_size_str.clear();
|
||||
self.manual.add_mountpoint.clear();
|
||||
self.manual.add_fstype = 0;
|
||||
// Akıllı varsayılan bağlama noktası
|
||||
self.manual.add_mountpoint = match next_num {
|
||||
1 if self.is_uefi => "/boot/efi".to_string(),
|
||||
1 => "/".to_string(),
|
||||
2 if self.is_uefi => "swap".to_string(),
|
||||
2 => "swap".to_string(),
|
||||
3 => "/".to_string(),
|
||||
_ => String::new(),
|
||||
};
|
||||
}
|
||||
// ── Butonlar: Yeni Bölüm / Düzenle / Sil ───────────
|
||||
ui.horizontal(|ui| {
|
||||
let has_selection = self.manual.selected_idx.is_some();
|
||||
let selected = self.manual.selected_idx
|
||||
.and_then(|i| state.custom_partitions.get(i));
|
||||
|
||||
// ── "Bölüm Ekle" diyaloğu ──────────────────────────────
|
||||
if self.manual.adding {
|
||||
egui::Window::new(t!("mp_add"))
|
||||
// Yeni Bölüm
|
||||
if theme::primary_button(ui, &format!("➕ {}", t!("mp_new_partition"))).clicked() {
|
||||
self.manual.adding = true;
|
||||
self.manual.editing = false;
|
||||
self.manual.edit_idx = None;
|
||||
let next_num = state.custom_partitions.len() + 1;
|
||||
self.manual.add_size_str.clear();
|
||||
self.manual.add_mountpoint.clear();
|
||||
self.manual.add_fstype = 0;
|
||||
self.manual.add_encrypt = false;
|
||||
self.manual.add_luks_password.clear();
|
||||
self.manual.add_mountpoint = match next_num {
|
||||
1 if self.is_uefi => "/boot/efi".to_string(),
|
||||
1 => "/".to_string(),
|
||||
2 if self.is_uefi => "swap".to_string(),
|
||||
2 => "swap".to_string(),
|
||||
3 => "/".to_string(),
|
||||
_ => String::new(),
|
||||
};
|
||||
}
|
||||
|
||||
// Düzenle
|
||||
ui.add_enabled_ui(has_selection, |ui| {
|
||||
if theme::secondary_button(ui, &format!("✏️ {}", t!("mp_edit_partition"))).clicked() {
|
||||
if let Some(part) = selected {
|
||||
self.manual.editing = true;
|
||||
self.manual.adding = false;
|
||||
self.manual.edit_idx = self.manual.selected_idx;
|
||||
self.manual.add_size_str = if part.size_mb == 0 {
|
||||
String::new()
|
||||
} else {
|
||||
part.size_mb.to_string()
|
||||
};
|
||||
self.manual.add_mountpoint = part.mountpoint.clone();
|
||||
self.manual.add_fstype = FS_OPTIONS.iter()
|
||||
.position(|(_, ft)| *ft == part.fstype)
|
||||
.unwrap_or(0);
|
||||
self.manual.add_encrypt = part.encrypt;
|
||||
self.manual.add_luks_password = part.luks_password.clone();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Sil
|
||||
ui.add_enabled_ui(has_selection, |ui| {
|
||||
if theme::danger_button(ui, &format!("🗑 {}", t!("mp_delete"))).clicked() {
|
||||
self.manual.delete_idx = self.manual.selected_idx;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// ── Bölüm Ekle / Düzenle diyaloğu ─────────────────
|
||||
let dialog_open = self.manual.adding || self.manual.editing;
|
||||
if dialog_open {
|
||||
let is_edit = self.manual.editing;
|
||||
let title = if is_edit { t!("mp_edit_partition") } else { t!("mp_new_partition") };
|
||||
egui::Window::new(title)
|
||||
.collapsible(false)
|
||||
.resizable(false)
|
||||
.anchor(egui::Align2::CENTER_CENTER, [0.0, 0.0])
|
||||
.show(ui.ctx(), |ui| {
|
||||
egui::Grid::new("add_part_grid")
|
||||
.num_columns(2)
|
||||
.spacing([12.0, 8.0])
|
||||
.show(ui, |ui| {
|
||||
|
||||
// Dosya sistemi (boyut önerisi ile)
|
||||
ui.label(t!("mp_fstype"));
|
||||
let prev_fs = self.manual.add_fstype;
|
||||
let fs_label = FS_OPTIONS.get(self.manual.add_fstype).map(|x| x.0).unwrap_or("?");
|
||||
theme::show_combo_box(ui, "fs_combo", fs_label, ui.available_width(), |ui, w| {
|
||||
for (i, (label, _)) in FS_OPTIONS.iter().enumerate() {
|
||||
theme::selectable_value(ui, &mut self.manual.add_fstype, i, *label, w);
|
||||
}
|
||||
});
|
||||
// FS tipi değişince akıllı boyut öner
|
||||
if prev_fs != self.manual.add_fstype && self.manual.add_size_str.is_empty() {
|
||||
let fs = FS_OPTIONS.get(self.manual.add_fstype).map(|x| &x.1);
|
||||
match fs {
|
||||
Some(FsType::Fat32) => self.manual.add_size_str = "300".to_string(),
|
||||
Some(FsType::Swap) => self.manual.add_size_str = format!("{}", recommended_swap_mb()),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
ui.end_row();
|
||||
|
||||
// Boyut
|
||||
ui.label(t!("mp_size_hint"));
|
||||
ui.text_edit_singleline(&mut self.manual.add_size_str);
|
||||
ui.end_row();
|
||||
|
||||
// Bağlama noktası (2 aşamalı: combo + input)
|
||||
ui.label(t!("mp_mountpoint"));
|
||||
ui.horizontal(|ui| {
|
||||
let current_mp = if self.manual.add_mountpoint.is_empty() {
|
||||
t!("mp_select_hint").to_string()
|
||||
} else {
|
||||
self.manual.add_mountpoint.clone()
|
||||
};
|
||||
theme::show_combo_box(ui, "mp_combo", ¤t_mp, 120.0, |ui, w| {
|
||||
for mp in COMMON_MOUNTPOINTS {
|
||||
theme::selectable_value(ui, &mut self.manual.add_mountpoint, mp.to_string(), *mp, w);
|
||||
}
|
||||
});
|
||||
let mp_field = egui::TextEdit::singleline(&mut self.manual.add_mountpoint)
|
||||
.hint_text(t!("mp_add_dialog_hint"));
|
||||
ui.add(mp_field);
|
||||
});
|
||||
ui.end_row();
|
||||
|
||||
// LUKS şifreleme
|
||||
ui.label(t!("luks_enable_root"));
|
||||
let fstype = FS_OPTIONS.get(self.manual.add_fstype).map(|x| x.1.clone()).unwrap_or(FsType::Ext4);
|
||||
let can_encrypt = matches!(fstype, FsType::Ext4 | FsType::Ext3 | FsType::Btrfs | FsType::Xfs);
|
||||
ui.add_enabled_ui(can_encrypt, |ui| {
|
||||
ui.checkbox(&mut self.manual.add_encrypt, "");
|
||||
});
|
||||
if !can_encrypt { self.manual.add_encrypt = false; }
|
||||
ui.end_row();
|
||||
|
||||
if self.manual.add_encrypt {
|
||||
ui.label(t!("luks_password"));
|
||||
let pw = &mut self.manual.add_luks_password;
|
||||
ui.horizontal(|ui| {
|
||||
if self.show_luks_password {
|
||||
ui.text_edit_singleline(pw);
|
||||
} else {
|
||||
ui.add(egui::TextEdit::singleline(pw).password(true));
|
||||
}
|
||||
let eye = if self.show_luks_password { "🙈" } else { "👁" };
|
||||
if ui.small_button(eye).clicked() {
|
||||
self.show_luks_password = !self.show_luks_password;
|
||||
}
|
||||
});
|
||||
ui.end_row();
|
||||
ui.label(t!("mp_fstype"));
|
||||
let prev_fs = self.manual.add_fstype;
|
||||
let fs_label = FS_OPTIONS.get(self.manual.add_fstype).map(|x| x.0).unwrap_or("?");
|
||||
theme::show_combo_box(ui, "fs_combo", fs_label, ui.available_width(), |ui, w| {
|
||||
for (i, (label, _)) in FS_OPTIONS.iter().enumerate() {
|
||||
theme::selectable_value(ui, &mut self.manual.add_fstype, i, *label, w);
|
||||
}
|
||||
});
|
||||
// FS tipi değişince akıllı boyut öner
|
||||
if !is_edit && prev_fs != self.manual.add_fstype && self.manual.add_size_str.is_empty() {
|
||||
let fs = FS_OPTIONS.get(self.manual.add_fstype).map(|x| &x.1);
|
||||
match fs {
|
||||
Some(FsType::Fat32) => self.manual.add_size_str = "300".to_string(),
|
||||
Some(FsType::Swap) => self.manual.add_size_str = format!("{}", recommended_swap_mb()),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
ui.add_space(6.0);
|
||||
form_label(ui, &t!("mp_size_hint"));
|
||||
ui.horizontal(|ui| {
|
||||
form_input_text(ui, &mut self.manual.add_size_str);
|
||||
let parsed: u64 = self.manual.add_size_str.trim().parse().unwrap_or(0);
|
||||
if parsed > 0 {
|
||||
ui.label(format!("{} MB", format_number_thousands(parsed)));
|
||||
} else {
|
||||
ui.label("MB");
|
||||
}
|
||||
});
|
||||
// Slider — kullanılabilir alan kadar
|
||||
let used_mb: u64 = state.custom_partitions.iter()
|
||||
.enumerate()
|
||||
.filter(|(i, p)| p.size_mb > 0 && Some(*i) != self.manual.edit_idx)
|
||||
.map(|(_, p)| p.size_mb)
|
||||
.sum();
|
||||
let avail_mb = (max_mb as u64).saturating_sub(used_mb).max(1);
|
||||
let mut size_val = self.manual.add_size_str.trim().parse::<f64>().unwrap_or(0.0);
|
||||
ui.add_space(2.0);
|
||||
if ui.add(egui::Slider::new(&mut size_val, 0.0..=avail_mb as f64)
|
||||
.show_value(false)
|
||||
.max_decimals(0)
|
||||
).changed() {
|
||||
if size_val == 0.0 {
|
||||
self.manual.add_size_str = "0".to_string();
|
||||
} else {
|
||||
self.manual.add_size_str = format!("{}", size_val as u64);
|
||||
}
|
||||
}
|
||||
|
||||
ui.add_space(6.0);
|
||||
ui.label(t!("mp_mountpoint"));
|
||||
ui.horizontal(|ui| {
|
||||
let current_mp = if self.manual.add_mountpoint.is_empty() {
|
||||
t!("mp_select_hint").to_string()
|
||||
} else {
|
||||
self.manual.add_mountpoint.clone()
|
||||
};
|
||||
theme::show_combo_box(ui, "mp_combo", ¤t_mp, 120.0, |ui, w| {
|
||||
for mp in COMMON_MOUNTPOINTS {
|
||||
theme::selectable_value(ui, &mut self.manual.add_mountpoint, mp.to_string(), *mp, w);
|
||||
}
|
||||
});
|
||||
form_input_text(ui, &mut self.manual.add_mountpoint);
|
||||
});
|
||||
|
||||
ui.add_space(6.0);
|
||||
ui.label(t!("luks_enable_root"));
|
||||
let fstype = FS_OPTIONS.get(self.manual.add_fstype).map(|x| x.1.clone()).unwrap_or(FsType::Ext4);
|
||||
let can_encrypt = matches!(fstype, FsType::Ext4 | FsType::Ext3 | FsType::Btrfs | FsType::Xfs);
|
||||
ui.add_enabled_ui(can_encrypt, |ui| {
|
||||
ui.checkbox(&mut self.manual.add_encrypt, "");
|
||||
});
|
||||
if !can_encrypt { self.manual.add_encrypt = false; }
|
||||
|
||||
if self.manual.add_encrypt {
|
||||
ui.add_space(6.0);
|
||||
ui.label(t!("luks_password"));
|
||||
let pw = &mut self.manual.add_luks_password;
|
||||
ui.horizontal(|ui| {
|
||||
if self.show_luks_password {
|
||||
ui.text_edit_singleline(pw);
|
||||
} else {
|
||||
ui.add(egui::TextEdit::singleline(pw).password(true));
|
||||
}
|
||||
let eye = if self.show_luks_password { "🙈" } else { "👁" };
|
||||
if ui.small_button(eye).clicked() {
|
||||
self.show_luks_password = !self.show_luks_password;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ui.add_space(8.0);
|
||||
ui.horizontal(|ui| {
|
||||
let ok_btn = egui::Button::new(t!("mp_add_btn")).fill(accent.gamma_multiply(0.2));
|
||||
if ui.add(ok_btn).clicked() {
|
||||
let ok_label = if is_edit { t!("mp_save") } else { t!("mp_add_btn") };
|
||||
if theme::primary_button(ui, &ok_label).clicked() {
|
||||
let size_mb: u64 = self.manual.add_size_str
|
||||
.trim().parse().unwrap_or(0);
|
||||
let mp = self.manual.add_mountpoint.trim().to_string();
|
||||
let fstype = FS_OPTIONS.get(self.manual.add_fstype).map(|x| x.1.clone()).unwrap_or(FsType::Ext4);
|
||||
let part_num = state.custom_partitions.len() + 1;
|
||||
let device = crate::installer::part_path(&disk, part_num as u32);
|
||||
let encrypt = self.manual.add_encrypt;
|
||||
let luks_password = if encrypt { self.manual.add_luks_password.clone() } else { String::new() };
|
||||
|
||||
if mp.is_empty() {
|
||||
self.manual.error = Some(t!("mp_error_empty_mountpoint").to_string());
|
||||
} else if is_edit {
|
||||
if let Some(idx) = self.manual.edit_idx {
|
||||
if idx < state.custom_partitions.len() {
|
||||
let device = state.custom_partitions[idx].device.clone();
|
||||
state.custom_partitions[idx] = CustomPartition {
|
||||
device,
|
||||
size_mb,
|
||||
fstype,
|
||||
mountpoint: mp,
|
||||
encrypt,
|
||||
luks_password,
|
||||
luks_name: String::new(),
|
||||
};
|
||||
}
|
||||
}
|
||||
self.manual.editing = false;
|
||||
self.manual.edit_idx = None;
|
||||
self.manual.selected_idx = None;
|
||||
self.manual.error = None;
|
||||
} else {
|
||||
let encrypt = self.manual.add_encrypt;
|
||||
let luks_password = if encrypt { self.manual.add_luks_password.clone() } else { String::new() };
|
||||
let part_num = state.custom_partitions.len() + 1;
|
||||
let device = crate::installer::part_path(&disk, part_num as u32);
|
||||
state.custom_partitions.push(CustomPartition {
|
||||
device,
|
||||
size_mb,
|
||||
@@ -993,8 +1108,10 @@ impl PartitionStep {
|
||||
self.manual.adding = false;
|
||||
}
|
||||
}
|
||||
if ui.button(t!("cancel")).clicked() {
|
||||
if theme::secondary_button(ui, &t!("cancel")).clicked() {
|
||||
self.manual.adding = false;
|
||||
self.manual.editing = false;
|
||||
self.manual.edit_idx = None;
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -1107,9 +1224,7 @@ impl PartitionStep {
|
||||
|
||||
ui.add_space(8.0);
|
||||
// "Logical Volume Ekle" butonu
|
||||
let lv_btn = egui::Button::new(format!("➕ {}", t!("lvm_lv_add")))
|
||||
.fill(accent.gamma_multiply(0.15));
|
||||
if ui.add(lv_btn).clicked() {
|
||||
if theme::primary_button(ui, &format!("➕ {}", t!("lvm_lv_add"))).clicked() {
|
||||
self.manual.adding_lv = true;
|
||||
self.manual.add_lv_name.clear();
|
||||
self.manual.add_lv_vg_idx = 0;
|
||||
@@ -1185,8 +1300,7 @@ impl PartitionStep {
|
||||
|
||||
ui.add_space(8.0);
|
||||
ui.horizontal(|ui| {
|
||||
let ok_btn = egui::Button::new(t!("mp_add_btn")).fill(accent.gamma_multiply(0.2));
|
||||
if ui.add(ok_btn).clicked() {
|
||||
if theme::primary_button(ui, &t!("mp_add_btn")).clicked() {
|
||||
let size_mb: u64 = self.manual.add_lv_size_str.trim().parse().unwrap_or(0);
|
||||
let mp = self.manual.add_lv_mountpoint.trim().to_string();
|
||||
let lv_name = self.manual.add_lv_name.trim().to_string();
|
||||
@@ -1219,7 +1333,7 @@ impl PartitionStep {
|
||||
self.manual.error = Some(t!("lvm_lv_error_vg").to_string());
|
||||
}
|
||||
}
|
||||
if ui.button(t!("cancel")).clicked() {
|
||||
if theme::secondary_button(ui, &t!("cancel")).clicked() {
|
||||
self.manual.adding_lv = false;
|
||||
}
|
||||
});
|
||||
@@ -1245,7 +1359,84 @@ impl PartitionStep {
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────
|
||||
// Yardımcı: renkli bölüm şeridi
|
||||
// Yardımcı: renkli bölüm şeridi (manuel)
|
||||
// ─────────────────────────────────────────────
|
||||
|
||||
fn manual_partition_bar(ui: &mut egui::Ui, parts: &[CustomPartition]) {
|
||||
let bar_height = 28.0;
|
||||
let (rect, _) = ui.allocate_exact_size(
|
||||
egui::vec2(ui.available_width(), bar_height),
|
||||
egui::Sense::hover(),
|
||||
);
|
||||
let painter = ui.painter();
|
||||
|
||||
if parts.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Each partition gets at least MIN_VISIBLE of the bar so all are visible
|
||||
let sized_total: f32 = parts.iter().map(|p| p.size_mb as f32).sum();
|
||||
let min_visible = 0.04;
|
||||
|
||||
let mut raw: Vec<f32> = parts.iter().map(|p| {
|
||||
if sized_total > 0.0 {
|
||||
(p.size_mb as f32 / sized_total).max(min_visible)
|
||||
} else {
|
||||
min_visible
|
||||
}
|
||||
}).collect();
|
||||
|
||||
// Normalize to sum 1.0
|
||||
let sum: f32 = raw.iter().sum();
|
||||
for v in raw.iter_mut() {
|
||||
*v /= sum;
|
||||
}
|
||||
|
||||
let mut segments: Vec<(&str, f32, egui::Color32)> = Vec::new();
|
||||
|
||||
for (i, part) in parts.iter().enumerate() {
|
||||
let label = part.mountpoint.as_str();
|
||||
let color = if part.fstype == FsType::Fat32 {
|
||||
egui::Color32::from_rgb(80, 160, 220)
|
||||
} else if part.fstype == FsType::Swap {
|
||||
egui::Color32::from_rgb(220, 160, 40)
|
||||
} else if part.mountpoint == "/" {
|
||||
egui::Color32::from_rgb(80, 190, 100)
|
||||
} else {
|
||||
egui::Color32::from_rgb(160, 130, 200)
|
||||
};
|
||||
segments.push((label, raw[i], color));
|
||||
}
|
||||
|
||||
let mut x = rect.left();
|
||||
let rounding = egui::Rounding::same(4.0);
|
||||
for (i, (label, frac, color)) in segments.iter().enumerate() {
|
||||
let w = frac * rect.width();
|
||||
let seg_rect = egui::Rect::from_min_size(
|
||||
egui::pos2(x, rect.top()),
|
||||
egui::vec2(w - 1.0, bar_height),
|
||||
);
|
||||
let seg_rounding = if i == 0 {
|
||||
egui::Rounding { nw: rounding.nw, sw: rounding.sw, ne: 0.0, se: 0.0 }
|
||||
} else if i == segments.len() - 1 {
|
||||
egui::Rounding { nw: 0.0, sw: 0.0, ne: rounding.ne, se: rounding.se }
|
||||
} else {
|
||||
egui::Rounding::ZERO
|
||||
};
|
||||
painter.rect_filled(seg_rect, seg_rounding, *color);
|
||||
painter.text(
|
||||
seg_rect.center(),
|
||||
egui::Align2::CENTER_CENTER,
|
||||
*label,
|
||||
egui::FontId::proportional(12.0),
|
||||
egui::Color32::WHITE,
|
||||
);
|
||||
x += w;
|
||||
}
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────
|
||||
// Yardımcı: renkli bölüm şeridi (otomatik)
|
||||
// ─────────────────────────────────────────────
|
||||
|
||||
fn partition_bar(ui: &mut egui::Ui, plan: &PartitionPlan) {
|
||||
@@ -1304,3 +1495,16 @@ fn partition_bar(ui: &mut egui::Ui, plan: &PartitionPlan) {
|
||||
x += w;
|
||||
}
|
||||
}
|
||||
|
||||
/// Sayıyı nokta ile binlik ayraçlı formata çevirir (örn. 7000000 → 7.000.000).
|
||||
fn format_number_thousands(n: u64) -> String {
|
||||
let s = n.to_string();
|
||||
let mut result = String::new();
|
||||
for (i, c) in s.chars().enumerate() {
|
||||
if i > 0 && (s.len() - i) % 3 == 0 {
|
||||
result.push('.');
|
||||
}
|
||||
result.push(c);
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
+16
-23
@@ -8,6 +8,8 @@ pub struct UsersStep {
|
||||
use_same_for_admin: bool,
|
||||
show_password: bool,
|
||||
show_password_confirm: bool,
|
||||
show_root_password: bool, // <-- Eklendi
|
||||
show_root_password_confirm: bool, // <-- Eklendi
|
||||
}
|
||||
|
||||
impl Default for UsersStep {
|
||||
@@ -16,6 +18,8 @@ impl Default for UsersStep {
|
||||
use_same_for_admin: true,
|
||||
show_password: false,
|
||||
show_password_confirm: false,
|
||||
show_root_password: false,
|
||||
show_root_password_confirm: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -151,7 +155,7 @@ impl InstallerStep for UsersStep {
|
||||
|
||||
// ─── Kullanıcı Bilgileri Formu ──────────────────────────────────
|
||||
egui::Frame::group(ui.style())
|
||||
.fill(theme::c_bg_widget())
|
||||
.fill(egui::Color32::from_rgb(240, 243, 198))
|
||||
.rounding(6.0)
|
||||
.inner_margin(egui::Margin::symmetric(10.0, 10.0))
|
||||
.show(ui, |ui| {
|
||||
@@ -200,6 +204,7 @@ impl InstallerStep for UsersStep {
|
||||
{
|
||||
let show_pwd = &mut self.show_password;
|
||||
let before = state.password.clone();
|
||||
|
||||
form_input_password(ui, &mut state.password, show_pwd);
|
||||
// Kullanıcı şifreyi değiştirdiyse OEM bayrağını kaldır
|
||||
if state.oem_mode && state.password != before {
|
||||
@@ -254,7 +259,7 @@ impl InstallerStep for UsersStep {
|
||||
} else {
|
||||
ui.add_space(8.0);
|
||||
egui::Frame::group(ui.style())
|
||||
.fill(theme::c_bg_widget())
|
||||
.fill(theme::c_root_bg())
|
||||
.rounding(6.0)
|
||||
.inner_margin(egui::Margin::same(12.0))
|
||||
.show(ui, |ui| {
|
||||
@@ -263,33 +268,21 @@ impl InstallerStep for UsersStep {
|
||||
ui.add_space(8.0);
|
||||
|
||||
// Root şifresi
|
||||
|
||||
ui.label(egui::RichText::new(t!("admin_password_label")).strong().color(theme::c_text()));
|
||||
ui.horizontal(|ui| {
|
||||
ui.add(
|
||||
eframe::egui::TextEdit::singleline(&mut state.root_password)
|
||||
.password(true)
|
||||
.desired_width(f32::INFINITY)
|
||||
.min_size(eframe::egui::vec2(0.0, 32.0))
|
||||
);
|
||||
|
||||
if !state.root_password.is_empty() && state.root_password.len() < 8 {
|
||||
ui.colored_label(theme::c_error(), t!("admin_password_short"));
|
||||
}
|
||||
});
|
||||
|
||||
// DÜZELTME: 3. parametre olarak show_root_password eklendi
|
||||
let show_root_pwd = &mut self.show_root_password;
|
||||
form_input_password(ui, &mut state.root_password, show_root_pwd);
|
||||
|
||||
ui.add_space(8.0);
|
||||
|
||||
// Şifre doğrulama
|
||||
ui.label(egui::RichText::new(t!("admin_password_confirm_label")).strong().color(theme::c_text()));
|
||||
|
||||
ui.horizontal(|ui| {
|
||||
ui.add(
|
||||
eframe::egui::TextEdit::singleline(&mut state.root_password_confirm)
|
||||
.password(true)
|
||||
.desired_width(f32::INFINITY)
|
||||
.min_size(eframe::egui::vec2(0.0, 32.0))
|
||||
);
|
||||
});
|
||||
// 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);
|
||||
|
||||
if state.root_password == state.root_password_confirm {
|
||||
ui.colored_label(theme::c_success(), "✅");
|
||||
} else {
|
||||
|
||||
+10
-3
@@ -47,6 +47,7 @@ pub fn c_error() -> Color32 { color_from_hex(ERROR.load(Ordering::Relaxed))
|
||||
pub fn c_sidebar() -> Color32 { color_from_hex(SIDEBAR.load(Ordering::Relaxed)) }
|
||||
pub fn c_sidebar_text() -> Color32 { color_from_hex(SIDEBAR_TEXT.load(Ordering::Relaxed)) }
|
||||
pub fn c_footer_bg() -> Color32 { color_from_hex(0xf7f7f7) }
|
||||
pub fn c_root_bg() -> Color32 { color_from_hex(0xf7f7f7) }
|
||||
|
||||
pub fn set_theme_mode(is_dark: bool) {
|
||||
if is_dark {
|
||||
@@ -271,7 +272,9 @@ pub fn error_box(ui: &mut egui::Ui, msg: &str) {
|
||||
.inner_margin(egui::Margin::same(10.0))
|
||||
.show(ui, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.colored_label(c_error(), "❌");
|
||||
ui.add(egui::Image::new(egui::include_image!("../../assets/icons/fail-icon.svg"))
|
||||
.max_width(18.0).max_height(18.0)
|
||||
.tint(c_error()));
|
||||
ui.colored_label(c_error(), msg);
|
||||
});
|
||||
});
|
||||
@@ -286,7 +289,9 @@ pub fn warning_box(ui: &mut egui::Ui, msg: &str) {
|
||||
.inner_margin(egui::Margin::same(10.0))
|
||||
.show(ui, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.colored_label(c_warning(), "⚠️");
|
||||
ui.add(egui::Image::new(egui::include_image!("../../assets/icons/warning-icon.svg"))
|
||||
.max_width(18.0).max_height(18.0)
|
||||
.tint(c_warning()));
|
||||
ui.colored_label(c_warning(), msg);
|
||||
});
|
||||
});
|
||||
@@ -301,7 +306,9 @@ pub fn success_box(ui: &mut egui::Ui, msg: &str) {
|
||||
.inner_margin(egui::Margin::same(10.0))
|
||||
.show(ui, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.colored_label(c_success(), "✅");
|
||||
ui.add(egui::Image::new(egui::include_image!("../../assets/icons/check.svg"))
|
||||
.max_width(18.0).max_height(18.0)
|
||||
.tint(c_success()));
|
||||
ui.colored_label(c_success(), msg);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user