use gtk4::prelude::*; use gtk4::{Box, Button, Orientation}; use serde::{Deserialize, Serialize}; use std::fs; use std::path::PathBuf; use webkit6::prelude::*; use webkit6::WebView; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Bookmark { pub name: String, pub url: String, } #[derive(Debug, Serialize, Deserialize)] pub struct Bookmarks { pub items: Vec, } impl Bookmarks { 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"); let _ = fs::create_dir_all(&path); path.push("bookmarks.toml"); path } pub fn load_from_file() -> Bookmarks { let path = Self::default_config_path(); if let Ok(content) = fs::read_to_string(path) { toml::from_str(&content).unwrap_or_else(|_| Bookmarks { items: vec![ Bookmark { name: "Reg.i2p".to_string(), url: "http://reg.i2p".to_string(), }, Bookmark { name: "Kislitsa forum".to_string(), url: "http://kislitsa.i2p/".to_string(), }, Bookmark { name: "Soundcloack".to_string(), url: "http://maidzones5taqt3g2boaepkxdi6f2etznqbfebludsl4i2ydrcjq.b32.i2p/".to_string(), }, ], }) } else { Bookmarks { items: vec![ Bookmark { name: "Reg.i2p".to_string(), url: "http://reg.i2p".to_string(), }, Bookmark { name: "Kislitsa forum".to_string(), url: "http://kislitsa.i2p/".to_string(), }, Bookmark { name: "Soundcloack".to_string(), url: "http://maidzones5taqt3g2boaepkxdi6f2etznqbfebludsl4i2ydrcjq.b32.i2p/".to_string(), }, ], } } } pub fn save_to_file(&self) -> Result<(), toml::ser::Error> { let path = Self::default_config_path(); let toml: String = toml::to_string(self)?; fs::write(path, toml) .expect("Failed to write bookmarks file"); Ok(()) } pub fn add_bookmark(&mut self, name: String, url: String) { self.items.push(Bookmark { name, url }); let _ = self.save_to_file(); } pub fn remove_bookmark(&mut self, index: usize) { if index < self.items.len() { self.items.remove(index); let _ = self.save_to_file(); } } } pub struct BookmarksBar { pub container: Box, bookmarks: Bookmarks, webview: Option, } impl BookmarksBar { pub fn new() -> Self { let container = Box::builder() .orientation(Orientation::Horizontal) .spacing(5) .margin_start(10) .margin_end(10) .margin_top(5) .margin_bottom(5) .build(); let mut bookmarks_bar = BookmarksBar { container, bookmarks: Bookmarks::load_from_file(), webview: None, }; bookmarks_bar.refresh_bookmarks(); bookmarks_bar } pub fn set_webview(&mut self, webview: &WebView) { self.webview = Some(webview.clone()); self.refresh_bookmarks(); } fn refresh_bookmarks(&mut self) { while let Some(child) = self.container.first_child() { self.container.remove(&child); } for bookmark in self.bookmarks.items.iter() { let button = Button::with_label(&bookmark.name); let url = bookmark.url.clone(); if let Some(ref webview) = self.webview { let webview_clone = webview.clone(); button.connect_clicked(move |_| { webview_clone.load_uri(&url); }); } self.container.append(&button); } let add_button = Button::with_label("+"); let webview_ref = self.webview.clone(); add_button.connect_clicked(move |_| { // TODO: Show dialog to add bookmark if let Some(ref webview) = webview_ref { if let Some(uri) = webview.uri() { println!("Add bookmark for current URL: {}", uri); } } }); self.container.append(&add_button); } pub fn add_current_page(&mut self, name: String, url: String) { self.bookmarks.add_bookmark(name, url); self.refresh_bookmarks(); } pub fn get_container(&self) -> &Box { &self.container } }