Files
yali-rs/src/ui/error_screen.rs
T
2026-05-22 23:35:27 +03:00

166 lines
5.8 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! Hata yakalama ve kullanıcıya bildirme ekranı.
//!
//! Kurulum sırasında kritik bir hata oluştuğunda
//! bu ekran tüm merkez paneli kaplar.
//! Log detayları açılıp kapanabilir; kullanıcı
//! hata raporunu panoya kopyalayabilir.
use eframe::egui;
use rust_i18n::t;
use crate::ui::theme;
pub struct ErrorScreen {
pub title: String,
pub message: String,
pub log_lines: Vec<String>,
log_expanded: bool,
copied: bool,
copied_timer: u8, // frame sayacı; 0 olunca "Kopyalandı" etiketi kaybolur
}
impl ErrorScreen {
pub fn new(title: impl Into<String>, message: impl Into<String>, log: Vec<String>) -> Self {
Self {
title: title.into(),
message: message.into(),
log_lines: log,
log_expanded: false,
copied: false,
copied_timer: 0,
}
}
/// Ekranı çizer. `on_retry` ve `on_quit` kapanışları buton basımlarında çağrılır.
pub fn show(
&mut self,
ui: &mut egui::Ui,
on_retry: impl FnOnce(),
on_quit: impl FnOnce(),
) {
// "Kopyalandı" zamanlayıcısını azalt
if self.copied && self.copied_timer > 0 {
self.copied_timer -= 1;
if self.copied_timer == 0 {
self.copied = false;
}
ui.ctx().request_repaint();
}
ui.add_space(24.0);
ui.vertical_centered(|ui| {
// ── Büyük hata simgesi ─────────────────────────
ui.label(
egui::RichText::new("")
.size(56.0)
.color(theme::c_error()),
);
ui.add_space(10.0);
// ── Başlık ────────────────────────────────────
ui.label(
egui::RichText::new(&self.title)
.size(22.0)
.strong()
.color(theme::c_text()),
);
ui.add_space(6.0);
// ── Hata mesajı ───────────────────────────────
egui::Frame::none()
.fill(egui::Color32::from_rgba_unmultiplied(0xF4, 0x43, 0x36, 18))
.stroke(egui::Stroke::new(1.0, theme::c_error()))
.rounding(egui::Rounding::same(8.0))
.inner_margin(egui::Margin::same(12.0))
.show(ui, |ui| {
ui.set_width(ui.available_width().min(560.0));
ui.colored_label(theme::c_error(), &self.message);
});
ui.add_space(16.0);
// ── Log bölümü (aç/kapat) ─────────────────────
let log_label = if self.log_expanded {
t!("error_hide_log")
} else {
t!("error_show_log")
};
if ui.button(log_label).clicked() {
self.log_expanded = !self.log_expanded;
}
if self.log_expanded {
ui.add_space(6.0);
egui::ScrollArea::vertical()
.max_height(180.0)
.id_source("error_log")
.show(ui, |ui| {
egui::Frame::none()
.fill(egui::Color32::from_rgb(14, 14, 22))
.rounding(egui::Rounding::same(6.0))
.inner_margin(egui::Margin::same(10.0))
.show(ui, |ui| {
ui.set_width(ui.available_width().min(560.0));
for line in &self.log_lines {
let color = log_line_color(line);
ui.colored_label(color, line);
}
});
});
ui.add_space(6.0);
// Panoya kopyala
let copy_label = if self.copied {
t!("error_copied")
} else {
t!("error_copy_log")
};
if ui.small_button(copy_label).clicked() && !self.copied {
let full_log = self.log_lines.join("\n");
ui.ctx().copy_text(full_log);
self.copied = true;
self.copied_timer = 120; // ~2 saniye (60fps varsayımı)
}
}
ui.add_space(20.0);
// ── Eylem butonları ───────────────────────────
ui.horizontal(|ui| {
// Ortalamak için boş genişlik hesapla
let btn_w = 140.0;
let gap = 16.0;
let total = btn_w * 2.0 + gap;
let side = (ui.available_width() - total) / 2.0;
ui.add_space(side.max(0.0));
if ui.add(theme::danger_button(&t!("error_quit"))).clicked() {
on_quit();
}
ui.add_space(gap);
if ui.add(theme::primary_button(&t!("error_retry"))).clicked() {
on_retry();
}
});
});
}
}
fn log_line_color(line: &str) -> egui::Color32 {
if line.starts_with('✗') || line.to_lowercase().contains("hata") || line.to_lowercase().contains("error") {
theme::c_error()
} else if line.starts_with('✓') {
theme::c_success()
} else if line.starts_with('▶') {
theme::c_accent()
} else if line.starts_with('⚠') {
theme::c_warning()
} else {
egui::Color32::from_rgb(180, 180, 200)
}
}