forked from pisilinux-rs/yali-rs
206 lines
8.5 KiB
Rust
206 lines
8.5 KiB
Rust
use eframe::egui;
|
||
use rust_i18n::t;
|
||
use crate::installer::{GlobalState, InstallerStep};
|
||
|
||
#[derive(Default)]
|
||
pub struct NetworkStep {
|
||
scan_results: Vec<WifiNetwork>,
|
||
show_password: Vec<bool>,
|
||
scanning: bool,
|
||
scan_done: bool,
|
||
proxy_enabled: bool,
|
||
}
|
||
|
||
#[derive(Clone, Default)]
|
||
struct WifiNetwork {
|
||
ssid: String,
|
||
signal: String,
|
||
secured: bool,
|
||
active: bool,
|
||
}
|
||
|
||
impl NetworkStep {
|
||
fn scan_wifi(&mut self) {
|
||
self.scanning = true;
|
||
self.scan_done = false;
|
||
self.scan_results.clear();
|
||
|
||
if let Ok(out) = std::process::Command::new("nmcli")
|
||
.args(["-t", "-f", "SSID,SIGNAL,SECURITY,ACTIVE", "dev", "wifi", "list"])
|
||
.output()
|
||
{
|
||
if out.status.success() {
|
||
let text = String::from_utf8_lossy(&out.stdout);
|
||
for line in text.lines() {
|
||
let parts: Vec<&str> = line.split(':').collect();
|
||
if parts.len() >= 3 {
|
||
let ssid = parts[0].trim().to_string();
|
||
if ssid.is_empty() || ssid == "--" { continue; }
|
||
self.scan_results.push(WifiNetwork {
|
||
ssid,
|
||
signal: parts[1].to_string(),
|
||
secured: !parts[2].is_empty() && parts[2] != "(none)" && parts[2] != "--",
|
||
active: parts.get(3).map(|s| s.trim() == "yes").unwrap_or(false),
|
||
});
|
||
}
|
||
}
|
||
}
|
||
}
|
||
self.show_password = vec![false; self.scan_results.len()];
|
||
self.scanning = false;
|
||
self.scan_done = true;
|
||
}
|
||
|
||
fn connect_wifi(ssid: &str, password: &str) -> Result<String, String> {
|
||
let mut args = vec!["dev", "wifi", "connect", ssid];
|
||
if !password.is_empty() {
|
||
args.extend_from_slice(&["password", password]);
|
||
}
|
||
let out = std::process::Command::new("nmcli")
|
||
.args(&args)
|
||
.output()
|
||
.map_err(|e| format!("nmcli error: {}", e))?;
|
||
if out.status.success() {
|
||
Ok(String::from_utf8_lossy(&out.stdout).trim().to_string())
|
||
} else {
|
||
Err(String::from_utf8_lossy(&out.stderr).trim().to_string())
|
||
}
|
||
}
|
||
}
|
||
|
||
impl InstallerStep for NetworkStep {
|
||
fn name(&self) -> String {
|
||
t!("network").to_string()
|
||
}
|
||
|
||
fn show(&mut self, ui: &mut egui::Ui, state: &mut GlobalState) {
|
||
ui.heading(t!("network_title"));
|
||
ui.label(t!("network_description"));
|
||
ui.add_space(12.0);
|
||
|
||
// Mevcut bağlantı durumu
|
||
if let Ok(out) = std::process::Command::new("nmcli")
|
||
.args(["-t", "-f", "DEVICE,TYPE,STATE,CONNECTION", "dev", "status"])
|
||
.output()
|
||
{
|
||
let text = String::from_utf8_lossy(&out.stdout);
|
||
let connected: Vec<&str> = text.lines()
|
||
.filter(|l| l.contains(":connected:") || l.contains(":connecting:"))
|
||
.collect();
|
||
if !connected.is_empty() {
|
||
ui.colored_label(
|
||
egui::Color32::from_rgb(80, 170, 80),
|
||
format!("{} {}", t!("network_connected"), connected.join(", ")),
|
||
);
|
||
} else {
|
||
ui.colored_label(
|
||
egui::Color32::from_rgb(200, 140, 40),
|
||
t!("network_disconnected"),
|
||
);
|
||
}
|
||
}
|
||
ui.add_space(8.0);
|
||
|
||
// Proxy ayarları
|
||
ui.horizontal(|ui| {
|
||
ui.add(egui::Checkbox::new(&mut self.proxy_enabled, ""));
|
||
ui.label(t!("network_proxy_label"));
|
||
});
|
||
if self.proxy_enabled {
|
||
egui::Grid::new("proxy_grid")
|
||
.num_columns(2)
|
||
.spacing([12.0, 6.0])
|
||
.show(ui, |ui| {
|
||
ui.label("HTTP:");
|
||
ui.text_edit_singleline(&mut state.network_http_proxy);
|
||
ui.end_row();
|
||
ui.label("HTTPS:");
|
||
ui.text_edit_singleline(&mut state.network_https_proxy);
|
||
ui.end_row();
|
||
ui.label("FTP:");
|
||
ui.text_edit_singleline(&mut state.network_ftp_proxy);
|
||
ui.end_row();
|
||
});
|
||
}
|
||
ui.add_space(12.0);
|
||
|
||
// Wi-Fi tara
|
||
if !self.scan_done {
|
||
if ui.add(egui::Button::new(t!("network_scan"))).clicked() {
|
||
self.scan_wifi();
|
||
}
|
||
} else {
|
||
ui.horizontal(|ui| {
|
||
if ui.add(egui::Button::new(t!("network_rescan"))).clicked() {
|
||
self.scan_done = false;
|
||
}
|
||
ui.label(
|
||
egui::RichText::new(format!("{}: {}", t!("network_scan_count"), self.scan_results.len()))
|
||
.size(12.0)
|
||
.color(egui::Color32::from_rgb(120, 120, 140)),
|
||
);
|
||
});
|
||
}
|
||
|
||
ui.add_space(6.0);
|
||
|
||
// Wi-Fi listesi
|
||
if !self.scan_results.is_empty() {
|
||
egui::ScrollArea::vertical()
|
||
.max_height(300.0)
|
||
.show(ui, |ui| {
|
||
egui::Frame::group(ui.style())
|
||
.inner_margin(egui::Margin::same(6.0))
|
||
.show(ui, |ui| {
|
||
for (i, net) in self.scan_results.clone().iter().enumerate() {
|
||
ui.horizontal(|ui| {
|
||
let lock = if net.secured { "🔒" } else { "🌐" };
|
||
let sig = net.signal.parse::<i32>().unwrap_or(0);
|
||
let bars = if sig > -50 { "▂▄▆█" } else if sig > -67 { "▂▄▆" } else if sig > -80 { "▂▄" } else { "▂" };
|
||
let active = if net.active { " ✓" } else { "" };
|
||
|
||
ui.label(format!("{} {}{}", lock, net.ssid, active));
|
||
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
|
||
ui.label(
|
||
egui::RichText::new(bars)
|
||
.size(10.0)
|
||
.color(egui::Color32::from_rgb(120, 120, 140)),
|
||
);
|
||
if net.secured && !net.active {
|
||
ui.add(egui::TextEdit::singleline(&mut state.network_wifi_password)
|
||
.password(!self.show_password.get(i).copied().unwrap_or(false))
|
||
.hint_text(t!("network_password_hint"))
|
||
.desired_width(120.0));
|
||
if ui.small_button("👁").clicked() {
|
||
if self.show_password.len() <= i {
|
||
self.show_password.resize(i + 1, false);
|
||
}
|
||
self.show_password[i] = !self.show_password[i];
|
||
}
|
||
}
|
||
if !net.active && ui.add(egui::Button::new(t!("network_connect"))).clicked() {
|
||
let pw = if net.secured { state.network_wifi_password.clone() } else { String::new() };
|
||
match Self::connect_wifi(&net.ssid, &pw) {
|
||
Ok(msg) => {
|
||
state.install_log.push(format!("Wi-Fi: {} — {}", net.ssid, msg));
|
||
self.scan_done = false;
|
||
}
|
||
Err(e) => {
|
||
state.install_log.push(format!("Wi-Fi error: {}", e));
|
||
}
|
||
}
|
||
}
|
||
});
|
||
});
|
||
ui.separator();
|
||
}
|
||
});
|
||
});
|
||
}
|
||
}
|
||
|
||
fn is_complete(&self, _state: &GlobalState) -> bool {
|
||
true
|
||
}
|
||
}
|