mod redirecting_i2p; mod settings_window; mod bookmarks; use gtk4::prelude::*; use gtk4::{ Application, ApplicationWindow, Box, Button, CheckButton, Entry, HeaderBar, Orientation, ScrolledWindow, }; use webkit6::prelude::*; use webkit6::{NetworkProxyMode, NetworkProxySettings, NetworkSession, WebView}; const APP_ID: &str = "com.namilsk.i2p-browser"; fn configure_i2p_proxy(enabled: bool) { if let Some(session) = NetworkSession::default() { if enabled { let settings = NetworkProxySettings::new(Some("http://127.0.0.1:4444"), &[]); session.set_proxy_settings(NetworkProxyMode::Custom, Some(&settings)); } else { session.set_proxy_settings(NetworkProxyMode::Default, None); } } } fn main() -> glib::ExitCode { let app = Application::builder().application_id(APP_ID).build(); app.connect_activate(build_ui); app.run() } fn build_ui(app: &Application) { let window = ApplicationWindow::builder() .application(app) .title("I2P Browser") .default_width(1024) .default_height(768) .build(); let header_bar = HeaderBar::new(); window.set_titlebar(Some(&header_bar)); let url_entry = Entry::builder() .placeholder_text("Enter I2P URL (e.g., http://example.i2p)") .build(); let button_back = Button::with_label("<"); let button_forward = Button::with_label(">"); let button_reload = Button::with_label("Restart"); let button_home = Button::with_label("Home"); let settings_button = Button::with_label("Settings"); let i2p_proxy = CheckButton::with_label("Enable i2p proxy"); let i2p_panel = Button::with_label("Panel"); let bookmark_button = Button::with_label("Bookmark"); header_bar.pack_start(&button_back); header_bar.pack_start(&button_forward); header_bar.pack_start(&button_reload); header_bar.pack_start(&button_home); header_bar.pack_end(&settings_button); header_bar.pack_end(&i2p_proxy); header_bar.pack_end(&i2p_panel); header_bar.pack_end(&bookmark_button); let main_box = Box::new(Orientation::Vertical, 0); window.set_child(Some(&main_box)); // Create bookmarks bar let bookmarks_bar = bookmarks::BookmarksBar::new(); // Use Rc for shared mutable access use std::rc::Rc; use std::cell::RefCell; let bookmarks_bar_shared = Rc::new(RefCell::new(bookmarks_bar)); if let Some(enabled) = settings_window::load_i2p_proxy_enabled() { i2p_proxy.set_active(enabled); configure_i2p_proxy(enabled); } i2p_proxy.connect_toggled(|btn| { let enabled = btn.is_active(); settings_window::save_i2p_proxy_enabled(enabled); configure_i2p_proxy(enabled); }); let web_view = WebView::new(); let scrolled_window = ScrolledWindow::builder().child(&web_view).build(); scrolled_window.set_vexpand(true); scrolled_window.set_hexpand(true); web_view.set_vexpand(true); web_view.set_hexpand(true); // Set webview for bookmarks bar bookmarks_bar_shared.borrow_mut().set_webview(&web_view); main_box.append(&url_entry); main_box.append(bookmarks_bar_shared.borrow().get_container()); if let Some(enable_js) = settings_window::load_js_enabled() && let Some(web_settings) = webkit6::prelude::WebViewExt::settings(&web_view) { web_settings.set_enable_javascript(enable_js); } main_box.append(&scrolled_window); let web_view_for_entry = web_view.clone(); let url_entry_for_entry = url_entry.clone(); url_entry.connect_activate(move |entry| { let url = entry.text().to_string(); let url_to_use = if !url.starts_with("http://") && !url.starts_with("https://") { format!("http://{}", url) } else { url }; let final_url = url_to_use; if glib::Uri::parse(&final_url, glib::UriFlags::NONE).is_ok() { web_view_for_entry.load_uri(&final_url); println!("Loading: {}", final_url); } else { eprintln!("Invalid URI: {}", final_url); } url_entry_for_entry.set_text(&final_url); }); let web_view_for_back = web_view.clone(); button_back.connect_clicked(move |_| { if web_view_for_back.can_go_back() { web_view_for_back.go_back(); } }); let web_view_for_forward = web_view.clone(); button_forward.connect_clicked(move |_| { if web_view_for_forward.can_go_forward() { web_view_for_forward.go_forward(); } }); let web_view_for_reload = web_view.clone(); button_reload.connect_clicked(move |_| { web_view_for_reload.reload(); }); let web_view_for_home = web_view.clone(); let url_entry_for_home = url_entry.clone(); button_home.connect_clicked(move |_| { let home_url = "http://reg.i2p/"; web_view_for_home.load_uri(home_url); url_entry_for_home.set_text(home_url); }); settings_button.connect_clicked(move |_| { settings_window::settings_window(); }); let url_entry_for_notify = url_entry.clone(); web_view.connect_notify_local(Some("uri"), move |web_view, _| { if let Some(uri) = web_view.uri() { url_entry_for_notify.set_text(&uri); } }); let web_view_for_panel = web_view.clone(); let _i2p_panel_for_open = i2p_panel.clone(); i2p_panel.connect_clicked(move |_| { let panel_port = redirecting_i2p::I2ProxySettings::from_i2pd_config(None) .ok() .and_then(|cfg| cfg.panel_port) .unwrap_or(7070); let i2p_panel_url = format!("http://127.0.0.1:{}/", panel_port); web_view_for_panel.load_uri(&i2p_panel_url); }); let web_view_for_bookmark = web_view.clone(); let bookmarks_bar_for_bookmark = bookmarks_bar_shared.clone(); bookmark_button.connect_clicked(move |_| { if let Some(uri) = web_view_for_bookmark.uri() { let dialog = gtk4::Dialog::builder() .title("Add Bookmark") .modal(true) .default_width(300) .build(); let content_area = dialog.content_area(); let entry_box = gtk4::Box::new(Orientation::Vertical, 5); entry_box.set_margin_top(10); entry_box.set_margin_bottom(10); entry_box.set_margin_start(10); entry_box.set_margin_end(10); let label = gtk4::Label::new(Some("Bookmark name:")); let name_entry = gtk4::Entry::new(); name_entry.set_text(&uri); entry_box.append(&label); entry_box.append(&name_entry); content_area.append(&entry_box); dialog.add_button("Cancel", gtk4::ResponseType::Cancel); dialog.add_button("Add", gtk4::ResponseType::Accept); let name_entry_for_response = name_entry.clone(); let uri_for_response = uri.clone(); let bookmarks_bar_clone = bookmarks_bar_for_bookmark.clone(); dialog.connect_response(move |dialog, response| { if response == gtk4::ResponseType::Accept { let name = name_entry_for_response.text().to_string(); bookmarks_bar_clone.borrow_mut().add_current_page(name, uri_for_response.to_string()); } dialog.close(); }); dialog.present(); } }); web_view.load_uri("http://legwork.i2p/"); window.present(); }