desktop: custom bookmark names

Bookmark names can now be changed by the user, defaults to the URL file.
This commit is contained in:
sleepycatcoding 2024-04-02 18:13:42 +03:00 committed by Nathan Adams
parent 231fbb7d66
commit 5cb9988183
5 changed files with 81 additions and 17 deletions

View File

@ -316,6 +316,7 @@ impl RuffleGui {
// FIXME: if spoof url is used, the URL here is incorrect (fun fact, its also incorrect in the debug tools).
match Url::from_str(player.swf().url()) {
Ok(url) => writer.add(crate::preferences::Bookmark {
name: crate::util::url_to_readable_name(&url).into_owned(),
url,
}),
Err(e) => tracing::warn!("Failed to parse SWF url for bookmark: {e}"),
@ -336,7 +337,7 @@ impl RuffleGui {
ui.separator();
self.preferences.bookmarks(|bookmarks| {
for bookmark in bookmarks.iter().filter(|x| !x.is_invalid()) {
if Button::new(crate::util::url_to_readable_name(&bookmark.url)).ui(ui).clicked() {
if Button::new(&bookmark.name).ui(ui).clicked() {
ui.close_menu();
let _ = self.event_loop.send_event(RuffleEvent::OpenURL(bookmark.url.clone(), Box::new(self.default_player_options.clone())));
}

View File

@ -1,13 +1,13 @@
use crate::gui::text;
use crate::gui::widgets::PathOrUrlField;
use crate::preferences::GlobalPreferences;
use crate::util::url_to_readable_name;
use egui::{Align2, Grid, Label, Sense, Ui, Window};
use egui_extras::{Column, TableBuilder};
use unic_langid::LanguageIdentifier;
struct SelectedBookmark {
index: usize,
name: String,
url: PathOrUrlField,
}
@ -94,11 +94,7 @@ impl BookmarksDialog {
}
row.col(|ui| {
ui.add(
Label::new(url_to_readable_name(&bookmark.url))
.selectable(false)
.wrap(false),
);
ui.add(Label::new(&bookmark.name).selectable(false).wrap(false));
});
row.col(|ui| {
ui.add(
@ -119,6 +115,7 @@ impl BookmarksDialog {
self.selected_bookmark = Some(SelectedBookmark {
index,
// TODO: set hint
name: bookmark.name.clone(),
url: PathOrUrlField::new(Some(bookmark.url.clone()), ""),
});
}
@ -145,11 +142,22 @@ impl BookmarksDialog {
Grid::new("bookmarks-dialog-panel-grid")
.num_columns(2)
.show(ui, |ui| {
ui.label(text(locale, "bookmarks-dialog-name"));
if ui.text_edit_singleline(&mut bookmark.name).lost_focus() {
if let Err(e) = self.preferences.write_bookmarks(|writer| {
writer.set_name(bookmark.index, bookmark.name.clone());
}) {
tracing::warn!("Couldn't update bookmarks: {e}");
}
}
ui.end_row();
let previous_url = bookmark.url.value().cloned();
ui.label(text(locale, "bookmarks-dialog-url"));
let current_url = bookmark.url.ui(locale, ui).value();
// TOOD: Change the UrlOrPathField widget to return a response instead, so we can update when we lose the focus, removes the need to clone every redraw.
if previous_url.as_ref() != current_url {
if let Some(url) = current_url {
if let Err(e) = self.preferences.write_bookmarks(|writer| {
@ -159,7 +167,6 @@ impl BookmarksDialog {
}
}
}
ui.end_row();
});
} else {

View File

@ -256,6 +256,7 @@ pub static INVALID_URL: &str = "invalid:///";
#[derive(Debug, PartialEq)]
pub struct Bookmark {
pub url: Url,
pub name: String,
}
impl Bookmark {

View File

@ -271,7 +271,13 @@ pub fn read_bookmarks(input: &str) -> (ParseResult<Vec<Bookmark>>, DocumentMut)
.expect("Url is constant and valid"),
};
result.result.push(Bookmark { url });
let name = match bookmark.parse_from_str(cx, "name") {
Some(value) => value,
// Fallback to using the URL as the name.
None => crate::util::url_to_readable_name(&url).into_owned(),
};
result.result.push(Bookmark { url, name });
}
});
@ -603,6 +609,7 @@ mod tests {
assert_eq!(
ParseResult {
result: vec![],
warnings: vec![
"Invalid bookmark: expected array of tables but found table".to_string()
]
@ -614,6 +621,7 @@ mod tests {
ParseResult {
result: vec![Bookmark {
url: Url::parse(crate::preferences::INVALID_URL).unwrap(),
name: "".to_string(),
}],
warnings: vec![],
},
@ -624,11 +632,26 @@ mod tests {
ParseResult {
result: vec![Bookmark {
url: Url::parse(crate::preferences::INVALID_URL).unwrap(),
name: "".to_string(),
}],
warnings: vec!["Invalid bookmark.url: unsupported value \"invalid\"".to_string()],
},
read_bookmarks("[[bookmark]]\nurl = \"invalid\"").0,
);
assert_eq!(
ParseResult {
result: vec![Bookmark {
url: Url::parse("https://ruffle.rs/logo-anim.swf").unwrap(),
name: "Logo SWF".to_string(),
}],
warnings: vec![],
},
read_bookmarks(
"[[bookmark]]\nurl = \"https://ruffle.rs/logo-anim.swf\"\nname = \"Logo SWF\""
)
.0
);
}
#[test]
@ -638,9 +661,11 @@ mod tests {
result: vec![
Bookmark {
url: Url::from_str("file:///home/user/example.swf").unwrap(),
name: "example.swf".to_string(),
},
Bookmark {
url: Url::from_str("https://ruffle.rs/logo-anim.swf").unwrap(),
name: "logo-anim.swf".to_string(),
}
],
warnings: vec![],
@ -662,15 +687,19 @@ mod tests {
result: vec![
Bookmark {
url: Url::from_str("file:///home/user/example.swf").unwrap(),
name: "example.swf".to_string(),
},
Bookmark {
url: Url::parse(crate::preferences::INVALID_URL).unwrap(),
name: "".to_string(),
},
Bookmark {
url: Url::parse(crate::preferences::INVALID_URL).unwrap(),
name: "".to_string(),
},
Bookmark {
url: Url::from_str("https://ruffle.rs/logo-anim.swf").unwrap(),
name: "logo-anim.swf".to_string(),
}
],

View File

@ -82,6 +82,7 @@ impl<'a> BookmarksWriter<'a> {
let table = self.get_underlying_table();
let mut bookmark_table = Table::new();
bookmark_table["url"] = value(bookmark.url.to_string());
bookmark_table["name"] = value(&bookmark.name);
table.push(bookmark_table);
self.0.values.push(bookmark);
}
@ -92,6 +93,12 @@ impl<'a> BookmarksWriter<'a> {
self.0.values[index].url = url;
}
pub fn set_name(&mut self, index: usize, name: String) {
let table = self.bookmark_table(index);
table["name"] = value(&name);
self.0.values[index].name = name;
}
pub fn remove(&mut self, index: usize) {
let table = self.get_underlying_table();
table.remove(index);
@ -242,6 +249,7 @@ mod tests {
use super::*;
use crate::preferences::read::read_bookmarks;
use std::str::FromStr;
use url::Url;
define_serialization_test_helpers!(read_bookmarks, BookmarksAndDocument, BookmarksWriter);
@ -251,14 +259,30 @@ mod tests {
"",
|writer| {
writer.add(Bookmark {
url: url::Url::from_str("file:///home/user/example.swf").unwrap(),
url: Url::from_str("file:///home/user/example.swf").unwrap(),
name: "example.swf".to_string(),
})
},
"[[bookmark]]\nurl = \"file:///home/user/example.swf\"\n",
"[[bookmark]]\nurl = \"file:///home/user/example.swf\"\nname = \"example.swf\"\n",
);
test("[[bookmark]]\nurl = \"file:///home/user/example.swf\"\n", |writer| writer.add(Bookmark {
url: url::Url::from_str("file:///home/user/another_file.swf").unwrap()
}), "[[bookmark]]\nurl = \"file:///home/user/example.swf\"\n\n[[bookmark]]\nurl = \"file:///home/user/another_file.swf\"\n");
url: Url::from_str("file:///home/user/another_file.swf").unwrap(),
name: "another_file.swf".to_string(),
}), "[[bookmark]]\nurl = \"file:///home/user/example.swf\"\n\n[[bookmark]]\nurl = \"file:///home/user/another_file.swf\"\nname = \"another_file.swf\"\n");
}
#[test]
fn modify_bookmark() {
test(
"[[bookmark]]\nurl = \"file:///example.swf\"\n",
|writer| writer.set_name(0, "Custom Name".to_string()),
"[[bookmark]]\nurl = \"file:///example.swf\"\nname = \"Custom Name\"\n",
);
test(
"[[bookmark]]\nurl = \"file:///example.swf\"\nname = \"example.swf\"",
|writer| writer.set_url(0, Url::parse("https://ruffle.rs/logo-anim.swf").unwrap()),
"[[bookmark]]\nurl = \"https://ruffle.rs/logo-anim.swf\"\nname = \"example.swf\"\n",
);
}
#[test]
@ -284,20 +308,22 @@ mod tests {
"[bookmark]",
|writer| {
writer.add(Bookmark {
url: url::Url::from_str("file:///test.swf").unwrap(),
url: Url::from_str("file:///test.swf").unwrap(),
name: "test.swf".to_string(),
})
},
"[[bookmark]]\nurl = \"file:///test.swf\"\n",
"[[bookmark]]\nurl = \"file:///test.swf\"\nname = \"test.swf\"\n",
);
test(
"bookmark = 1010",
|writer| {
writer.add(Bookmark {
url: url::Url::from_str("file:///test.swf").unwrap(),
url: Url::from_str("file:///test.swf").unwrap(),
name: "test.swf".to_string(),
})
},
"[[bookmark]]\nurl = \"file:///test.swf\"\n",
"[[bookmark]]\nurl = \"file:///test.swf\"\nname = \"test.swf\"\n",
);
}
}