use gtk4::prelude::*; use gtk4::{ApplicationWindow, Box, Button, CheckButton, Entry, HeaderBar, Label, Orientation}; use serde::{Deserialize, Serialize}; use std::fs; use std::path::PathBuf; use crate::redirecting_i2p::I2ProxySettings; #[allow(dead_code)] #[derive(Debug, Serialize, Deserialize)] struct Settings { js: bool, outproxy: bool, i2p_proxy: bool, web_rtc: bool, home_addr: String, proxy_port: Option, panel_port: Option, } pub fn settings_window() { let app = ApplicationWindow::builder() .title("Settings") .default_width(400) .default_height(300) .build(); let header_bar = HeaderBar::new(); app.set_titlebar(Some(&header_bar)); let main_box = Box::new(Orientation::Vertical, 0); app.set_child(Some(&main_box)); let label = Label::new(Some("Most wanted features")); main_box.append(&label); let javascript = CheckButton::with_label("Enable JS"); let outproxy = CheckButton::with_label("Enable outproxy"); let i2pproxy = CheckButton::with_label("Enable i2p proxy"); let webrtc = CheckButton::with_label("Enable WebRTC"); let load = Button::with_label("Load"); let load_i2pd_conf = Button::with_label("Load from i2pd conf"); main_box.append(&javascript); main_box.append(&outproxy); main_box.append(&i2pproxy); main_box.append(&webrtc); let homeaddr = Entry::new(); homeaddr.set_placeholder_text(Some("Enter home address")); main_box.append(&homeaddr); let proxy_port_entry = Entry::new(); proxy_port_entry.set_placeholder_text(Some("Proxy port")); main_box.append(&proxy_port_entry); let panel_port_entry = Entry::new(); panel_port_entry.set_placeholder_text(Some("Panel port")); main_box.append(&panel_port_entry); main_box.append(&load); main_box.append(&load_i2pd_conf); let save = Button::with_label("Save"); main_box.append(&save); if let Some(settings) = Settings::load_from_default_file() { settings.apply_to_widgets( &javascript, &outproxy, &i2pproxy, &webrtc, &homeaddr, &proxy_port_entry, &panel_port_entry, ); } let javascript_for_save = javascript.clone(); let outproxy_for_save = outproxy.clone(); let i2pproxy_for_save = i2pproxy.clone(); let webrtc_for_save = webrtc.clone(); let homeaddr_for_save = homeaddr.clone(); let proxy_port_for_save = proxy_port_entry.clone(); let panel_port_for_save = panel_port_entry.clone(); save.connect_clicked(move |_| { let settings = Settings::from_widgets( &javascript_for_save, &outproxy_for_save, &i2pproxy_for_save, &webrtc_for_save, &homeaddr_for_save, &proxy_port_for_save, &panel_port_for_save, ); if let Err(err) = Settings::serialize_write(&Settings::default_config_path(), &settings) { eprintln!("Failed to save settings: {err}"); } }); let javascript_for_load = javascript.clone(); let outproxy_for_load = outproxy.clone(); let i2pproxy_for_load = i2pproxy.clone(); let webrtc_for_load = webrtc.clone(); let homeaddr_for_load = homeaddr.clone(); let proxy_port_for_load = proxy_port_entry.clone(); let panel_port_for_load = panel_port_entry.clone(); load.connect_clicked(move |_| { if let Some(settings) = Settings::load_from_default_file() { settings.apply_to_widgets( &javascript_for_load, &outproxy_for_load, &i2pproxy_for_load, &webrtc_for_load, &homeaddr_for_load, &proxy_port_for_load, &panel_port_for_load, ); } }); let proxy_port_for_i2pd = proxy_port_entry.clone(); let panel_port_for_i2pd = panel_port_entry.clone(); let i2pproxy_for_i2pd = i2pproxy.clone(); load_i2pd_conf.connect_clicked(move |_| { match I2ProxySettings::from_i2pd_config(None) { Ok(cfg) => { if let Some(port) = cfg.i2p_port { proxy_port_for_i2pd.set_text(&port.to_string()); i2pproxy_for_i2pd.set_active(true); } if let Some(port) = cfg.panel_port { panel_port_for_i2pd.set_text(&port.to_string()); } } Err(err) => { eprintln!("Failed to load i2pd config: {err}"); } } }); app.present(); } #[allow(dead_code)] impl Settings { fn default_config_path() -> PathBuf { let home = std::env::var("HOME").unwrap_or_else(|_| String::from(".")); let mut path = PathBuf::from(home); path.push(".config"); path.push("i2p-browser"); // Best effort to ensure directory exists let _ = fs::create_dir_all(&path); path.push("settings.toml"); path } fn from_widgets( javascript: &CheckButton, outproxy: &CheckButton, i2p_proxy: &CheckButton, web_rtc: &CheckButton, home_addr: &Entry, proxy_port_entry: &Entry, panel_port_entry: &Entry, ) -> Settings { let proxy_port = proxy_port_entry .text() .trim() .parse::() .ok(); let panel_port = panel_port_entry .text() .trim() .parse::() .ok(); Settings { js: javascript.is_active(), outproxy: outproxy.is_active(), i2p_proxy: i2p_proxy.is_active(), web_rtc: web_rtc.is_active(), home_addr: home_addr.text().to_string(), proxy_port, panel_port, } } fn apply_to_widgets( &self, javascript: &CheckButton, outproxy: &CheckButton, i2p_proxy: &CheckButton, web_rtc: &CheckButton, home_addr: &Entry, proxy_port_entry: &Entry, panel_port_entry: &Entry, ) { javascript.set_active(self.js); outproxy.set_active(self.outproxy); i2p_proxy.set_active(self.i2p_proxy); web_rtc.set_active(self.web_rtc); home_addr.set_text(&self.home_addr); if let Some(port) = self.proxy_port { proxy_port_entry.set_text(&port.to_string()); } else { proxy_port_entry.set_text(""); } if let Some(port) = self.panel_port { panel_port_entry.set_text(&port.to_string()); } else { panel_port_entry.set_text(""); } } fn load_from_default_file() -> Option { let path = Self::default_config_path(); let content = fs::read_to_string(path).ok()?; toml::from_str(&content).ok() } pub fn serialize_write( path: &std::path::Path, setts: &Settings, ) -> Result<(), toml::ser::Error> { let toml: String = toml::to_string(setts)?; std::fs::write(path, toml) .expect("Some error occurred, is permission granted to ~/.config?"); Ok(()) } } pub fn load_js_enabled() -> Option { Settings::load_from_default_file().map(|s| s.js) } pub fn load_i2p_proxy_enabled() -> Option { Settings::load_from_default_file().map(|s| s.i2p_proxy) } pub fn save_i2p_proxy_enabled(enabled: bool) { let mut settings = Settings::load_from_default_file().unwrap_or(Settings { js: true, outproxy: false, i2p_proxy: enabled, web_rtc: false, home_addr: String::new(), panel_port: Some(7070), proxy_port: Some(4444), }); settings.i2p_proxy = enabled; if let Err(err) = Settings::serialize_write(&Settings::default_config_path(), &settings) { eprintln!("Failed to save i2p proxy setting: {err}"); } }