feat: gradient buttons, language selector with flags, SVG support, and UI improvements

- Add linear gradient backgrounds to primary/secondary/danger buttons
- Add language selector with flag icons in ComboBox
- Add SVG support via egui_extras feature
- Add cancel confirmation dialog on exit
- Update Yali logo to SVG icon
- Add flag SVGs for all countries
- Improve users step layout with form helpers
- Refactor button API (ui::theme::*_button now takes ui param)
This commit is contained in:
Erkan IŞIK
2026-06-14 22:40:52 +03:00
parent b9f6df272e
commit a48120b039
305 changed files with 12323 additions and 445 deletions
+78 -53
View File
@@ -4,6 +4,7 @@ mod jobs;
mod ui;
mod autoinstall;
mod branding;
mod funct;
use installer::{GlobalState, InstallerStep, WelcomeStep, LocationStep};
use steps::{KeyboardStep, UsersStep, SummaryStep, ExecutionStep, FinishStep, PartitionStep, BootloaderStep, NetworkStep, DisplayManagerStep};
@@ -16,6 +17,7 @@ fn main() -> eframe::Result<()> {
// ── CLI: otomatik kurulum modu ───────────────────────
let args: Vec<String> = std::env::args().collect();
let demo_mode = args.contains(&"--demo".to_string());
if let Some(pos) = args.iter().position(|a| a == "--auto-install") {
if let Some(path) = args.get(pos + 1) {
@@ -31,6 +33,7 @@ fn main() -> eframe::Result<()> {
/// Grafik arayüzü başlatır (normal mod).
fn run_gui(demo_mode: bool) -> eframe::Result<()> {
let options = eframe::NativeOptions {
viewport: egui::ViewportBuilder::default()
.with_inner_size([1200.0, 900.0])
@@ -45,8 +48,8 @@ fn run_gui(demo_mode: bool) -> eframe::Result<()> {
Box::new(move |cc| {
// Görsel yükleyicileri etkinleştir (PNG desteği)
egui_extras::install_image_loaders(&cc.egui_ctx);
ui::theme::apply(&cc.egui_ctx, true);
ui::theme::set_theme_mode(false);
ui::theme::apply(&cc.egui_ctx, false);
let mut app = YaliApp::default();
app.state.demo_mode = demo_mode;
Box::new(app)
@@ -202,12 +205,13 @@ fn run_auto_install(path: &str, demo_mode: bool) -> eframe::Result<()> {
}
struct YaliApp {
state: GlobalState,
steps: Vec<Box<dyn InstallerStep>>,
rescue_step: Option<Box<dyn InstallerStep>>,
last_step: usize,
branding: branding::BrandingConfig,
loaded_language: String,
state: GlobalState,
steps: Vec<Box<dyn InstallerStep>>,
rescue_step: Option<Box<dyn InstallerStep>>,
last_step: usize,
branding: branding::BrandingConfig,
loaded_language: String,
show_cancel_dialog: bool,
}
impl Default for YaliApp {
@@ -233,6 +237,7 @@ impl Default for YaliApp {
last_step: usize::MAX,
branding: branding.clone(),
loaded_language: String::new(),
show_cancel_dialog: false,
};
// OEM modu: varsayılan değerleri ata ve step engelleme
@@ -347,17 +352,17 @@ impl eframe::App for YaliApp {
);
}
ui.add_space(8.0);
ui.label(
egui::RichText::new(t!("app_name"))
.strong()
.size(16.0)
.color(ui::theme::c_text_dim()),
);
// ui.label(
// egui::RichText::new(t!("app_name"))
// .strong()
// .size(16.0)
// .color(ui::theme::c_text_dim()),
// );
ui.colored_label(
egui::Color32::from_rgb(60, 60, 90),
format!("{}: {}", t!("version"), env!("CARGO_PKG_VERSION")),
);
// ui.colored_label(
// egui::Color32::from_rgb(60, 60, 90),
// format!("{}: {}", t!("version"), env!("CARGO_PKG_VERSION")),
// );
});
ui.add_space(16.0);
@@ -366,7 +371,8 @@ impl eframe::App for YaliApp {
// Adım listesi
for (i, step) in self.steps.iter().enumerate() {
let label = format!("{}. {}", i + 1, step.name());
//let label = format!("{}. {}", i + 1, step.name());
let label = step.name();
egui::Frame::none()
.fill(if i == cur {
@@ -374,23 +380,23 @@ impl eframe::App for YaliApp {
} else {
egui::Color32::TRANSPARENT
})
.rounding(egui::Rounding::same(6.0))
//.rounding(egui::Rounding::same(6.0))
.inner_margin(egui::Margin::symmetric(10.0, 5.0))
.show(ui, |ui| {
ui.set_width(175.0);
if i == cur {
ui.horizontal(|ui| {
ui.colored_label(ui::theme::c_accent(), "▶");
ui.colored_label(ui::theme::c_text(), label);
ui.colored_label(ui::theme::c_sidebar_text(), label);
});
} else if i < cur {
ui.horizontal(|ui| {
ui.colored_label(ui::theme::c_success(), "✅");
ui.colored_label(ui::theme::c_text_dim(), label);
ui.colored_label(ui::theme::c_sidebar_text(), label);
});
} else {
ui.colored_label(
egui::Color32::from_rgb(80, 80, 100),
egui::Color32::from_rgb(255, 255, 255),
format!(" {}", label),
);
}
@@ -400,39 +406,35 @@ impl eframe::App for YaliApp {
}
// Alt kısım: tema değiştirme
ui.with_layout(egui::Layout::bottom_up(egui::Align::Center), |ui| {
ui.add_space(6.0);
// ui.with_layout(egui::Layout::bottom_up(egui::Align::Center), |ui| {
// ui.add_space(6.0);
let theme_icon = if self.state.is_dark { "☀" } else { "🌙" };
let theme_label = if self.state.is_dark { "Light" } else { "Dark" };
if ui.add(
egui::Button::new(
egui::RichText::new(format!("{} {}", theme_icon, theme_label))
.size(12.0)
)
.rounding(egui::Rounding::same(6.0))
.min_size(egui::Vec2::new(100.0, 28.0))
).clicked() {
self.state.is_dark = !self.state.is_dark;
ui::theme::set_theme_mode(self.state.is_dark);
ui::theme::apply(ctx, self.state.is_dark);
}
});
// let theme_icon = if self.state.is_dark { "☀" } else { "🌙" };
// let theme_label = if self.state.is_dark { "Light" } else { "Dark" };
// if ui.add(
// egui::Button::new(
// egui::RichText::new(format!("{} {}", theme_icon, theme_label))
// .size(12.0)
// )
// .rounding(egui::Rounding::same(6.0))
// .min_size(egui::Vec2::new(100.0, 28.0))
// ).clicked() {
// self.state.is_dark = !self.state.is_dark;
// ui::theme::set_theme_mode(self.state.is_dark);
// ui::theme::apply(ctx, self.state.is_dark);
// }
// });
});
// ── Alt panel: navigasyon ────────────────────────────
egui::TopBottomPanel::bottom("footer")
.frame(egui::Frame::none()
.fill(ui::theme::c_bg_panel())
.stroke(egui::Stroke::new(1.0, ui::theme::c_border())))
.fill(ui::theme::c_footer_bg())
.stroke(egui::Stroke::new(1.0, ui::theme::c_footer_bg())))
.show(ctx, |ui| {
ui.add_space(10.0);
ui.horizontal(|ui| {
ui.add_space(8.0);
if !is_exec && !is_finish && ui.add(ui::theme::secondary_button(&t!("cancel"))).clicked() {
ctx.send_viewport_cmd(egui::ViewportCommand::Close);
}
ui.add_space(8.0);
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
ui.add_space(8.0);
@@ -449,19 +451,22 @@ impl eframe::App for YaliApp {
} else {
t!("next")
};
let btn = if is_valid {
ui::theme::primary_button(&next_label)
} else {
ui::theme::secondary_button(&next_label)
if !is_exec && !is_finish && ui::theme::danger_button(ui, &t!("cancel")).clicked() {
self.show_cancel_dialog = true;
};
if ui.add_enabled(is_valid, btn).clicked() {
let next_clicked = if is_valid {
ui::theme::primary_button(ui, &next_label).clicked()
} else {
ui::theme::secondary_button(ui, &next_label).clicked()
};
if next_clicked {
self.state.current_step += 1;
}
}
if cur > 0 && !is_exec {
ui.add_space(8.0);
if ui.add(ui::theme::secondary_button(&t!("back"))).clicked() {
if ui::theme::secondary_button(ui, &t!("back")).clicked() {
self.state.current_step -= 1;
}
}
@@ -471,6 +476,26 @@ impl eframe::App for YaliApp {
ui.add_space(10.0);
});
// ── İptal onay diyaloğu ───────────────────────────────
if self.show_cancel_dialog {
egui::Window::new(t!("cancel_confirm_title"))
.collapsible(false)
.resizable(false)
.anchor(egui::Align2::CENTER_CENTER, [0.0, 0.0])
.show(ctx, |ui| {
ui.label(t!("cancel_confirm_msg"));
ui.add_space(12.0);
ui.horizontal(|ui| {
if ui.button(t!("cancel_confirm_yes")).clicked() {
ctx.send_viewport_cmd(egui::ViewportCommand::Close);
}
if ui.button(t!("cancel_confirm_no")).clicked() {
self.show_cancel_dialog = false;
}
});
});
}
// ── Merkez panel ─────────────────────────────────────
egui::CentralPanel::default()
.frame(egui::Frame::none()