desktop: redesign bookmark UI

lets be fair, the previous one was ugly + this one allows you to actually
change the URL!
This commit is contained in:
sleepycatcoding 2024-04-01 22:14:58 +03:00 committed by Nathan Adams
parent 077cf7c77b
commit 231fbb7d66
5 changed files with 181 additions and 53 deletions

View File

@ -1 +1,7 @@
bookmarks-dialog = Manage Bookmarks
bookmarks-dialog-name = Name
bookmarks-dialog-location = Location
bookmarks-dialog-url = URL
bookmarks-dialog-no-bookmarks = There are no bookmarks right now
bookmarks-dialog-not-selected = Nothing to show

View File

@ -327,26 +327,21 @@ impl RuffleGui {
}
});
let mut have_bookmarks = false;
if Button::new(text(locale, "bookmarks-menu-manage")).ui(ui).clicked() {
ui.close_menu();
self.open_bookmarks();
}
self.preferences.bookmarks(|bookmarks| {
have_bookmarks = !bookmarks.is_empty();
if have_bookmarks {
if self.preferences.have_bookmarks() {
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() {
ui.close_menu();
let _ = self.event_loop.send_event(RuffleEvent::OpenURL(bookmark.url.clone(), Box::new(self.default_player_options.clone())));
}
}
ui.separator();
}
});
if have_bookmarks && Button::new(text(locale, "bookmarks-menu-manage")).ui(ui).clicked() {
ui.close_menu();
self.open_bookmarks();
}
});
menu::menu_button(ui, text(locale, "debug-menu"), |ui| {

View File

@ -1,66 +1,171 @@
use crate::gui::text;
use crate::gui::widgets::PathOrUrlField;
use crate::preferences::GlobalPreferences;
use egui::{Align2, Button, Grid, Widget, Window};
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,
url: PathOrUrlField,
}
pub struct BookmarksDialog {
preferences: GlobalPreferences,
selected_bookmark: Option<SelectedBookmark>,
}
impl BookmarksDialog {
pub fn new(preferences: GlobalPreferences) -> Self {
Self { preferences }
Self {
preferences,
selected_bookmark: None,
}
}
pub fn show(&mut self, locale: &LanguageIdentifier, egui_ctx: &egui::Context) -> bool {
let mut keep_open = true;
let mut should_close = false;
let should_close = false;
Window::new(text(locale, "bookmarks-dialog"))
.open(&mut keep_open)
.anchor(Align2::CENTER_CENTER, egui::Vec2::ZERO)
.collapsible(false)
.resizable(false)
.default_width(600.0)
.default_height(400.0)
.show(egui_ctx, |ui| {
Grid::new("bookmarks-dialog-grid")
.num_columns(2)
.striped(true)
.show(ui, |ui| {
egui::TopBottomPanel::top("bookmark-dialog-top-panel")
.resizable(true)
.min_height(100.0)
.show_inside(ui, |ui| {
if self.preferences.have_bookmarks() {
self.show_bookmark_table(locale, ui);
} else {
ui.centered_and_justified(|ui| {
ui.label(text(locale, "bookmarks-dialog-no-bookmarks"));
});
}
});
self.show_bookmark_panel(locale, ui);
});
keep_open && !should_close
}
fn show_bookmark_table(&mut self, locale: &LanguageIdentifier, ui: &mut Ui) {
let text_height = egui::TextStyle::Body
.resolve(ui.style())
.size
.max(ui.spacing().interact_size.y);
enum BookmarkAction {
Remove(usize),
}
let mut action = None;
TableBuilder::new(ui)
.striped(true)
.resizable(true)
.column(Column::auto())
.column(Column::remainder())
.sense(Sense::click())
.header(20.0, |mut header| {
header.col(|ui| {
ui.strong(text(locale, "bookmarks-dialog-name"));
});
header.col(|ui| {
ui.strong(text(locale, "bookmarks-dialog-location"));
});
})
.body(|mut body| {
self.preferences.bookmarks(|bookmarks| {
// Close the dialog if we have no bookmarks to show.
should_close = bookmarks.is_empty();
for (index, bookmark) in bookmarks.iter().enumerate() {
if bookmark.is_invalid() {
continue;
}
for (index, bookmark) in
bookmarks.iter().filter(|x| !x.is_invalid()).enumerate()
{
ui.label(bookmark.url.as_str());
body.row(text_height, |mut row| {
if let Some(selected) = &self.selected_bookmark {
row.set_selected(index == selected.index);
}
if Button::new(text(locale, "remove")).ui(ui).clicked() {
row.col(|ui| {
ui.add(
Label::new(url_to_readable_name(&bookmark.url))
.selectable(false)
.wrap(false),
);
});
row.col(|ui| {
ui.add(
Label::new(bookmark.url.as_str())
.selectable(false)
.wrap(false),
);
});
let response = row.response();
response.context_menu(|ui| {
if ui.button(text(locale, "remove")).clicked() {
ui.close_menu();
action = Some(BookmarkAction::Remove(index));
}
ui.end_row();
});
if response.clicked() {
self.selected_bookmark = Some(SelectedBookmark {
index,
// TODO: set hint
url: PathOrUrlField::new(Some(bookmark.url.clone()), ""),
});
}
});
}
});
});
if let Some(action) = action {
if let Err(e) =
self.preferences.write_bookmarks(|writer| match action {
BookmarkAction::Remove(index) => writer.remove(index),
})
{
if let Err(e) = self.preferences.write_bookmarks(|writer| match action {
BookmarkAction::Remove(index) => {
// TODO: Recalculate the index for the selected bookmark, if it survives, otherwise just set to None.
self.selected_bookmark = None;
writer.remove(index);
}
}) {
tracing::warn!("Couldn't update bookmarks: {e}");
}
}
});
});
}
keep_open && !should_close
fn show_bookmark_panel(&mut self, locale: &LanguageIdentifier, ui: &mut Ui) {
if let Some(bookmark) = &mut self.selected_bookmark {
Grid::new("bookmarks-dialog-panel-grid")
.num_columns(2)
.show(ui, |ui| {
let previous_url = bookmark.url.value().cloned();
ui.label(text(locale, "bookmarks-dialog-url"));
let current_url = bookmark.url.ui(locale, ui).value();
if previous_url.as_ref() != current_url {
if let Some(url) = current_url {
if let Err(e) = self.preferences.write_bookmarks(|writer| {
writer.set_url(bookmark.index, url.clone());
}) {
tracing::warn!("Couldn't update bookmarks: {e}");
}
}
}
ui.end_row();
});
} else {
ui.vertical_centered_justified(|ui| {
ui.label(text(locale, "bookmarks-dialog-not-selected"));
});
}
}
}

View File

@ -151,10 +151,20 @@ impl GlobalPreferences {
fun(&self
.bookmarks
.lock()
.expect("Bookmarks is no reentrant")
.expect("Bookmarks is not reentrant")
.values)
}
pub fn have_bookmarks(&self) -> bool {
let bookmarks = &self
.bookmarks
.lock()
.expect("Bookmarks is not reentrant")
.values;
!bookmarks.is_empty() && !bookmarks.iter().all(|x| x.is_invalid())
}
pub fn write_preferences(&self, fun: impl FnOnce(&mut PreferencesWriter)) -> Result<(), Error> {
let mut preferences = self
.preferences

View File

@ -58,6 +58,12 @@ impl<'a> BookmarksWriter<'a> {
Self(bookmarks)
}
fn bookmark_table(&mut self, index: usize) -> &mut Table {
self.get_underlying_table()
.get_mut(index)
.expect("invalid bookmark index")
}
fn get_underlying_table(&mut self) -> &mut ArrayOfTables {
if self.0.toml_document.contains_array_of_tables("bookmark") {
return self.0.toml_document["bookmark"]
@ -80,6 +86,12 @@ impl<'a> BookmarksWriter<'a> {
self.0.values.push(bookmark);
}
pub fn set_url(&mut self, index: usize, url: url::Url) {
let table = self.bookmark_table(index);
table["url"] = value(url.as_str());
self.0.values[index].url = url;
}
pub fn remove(&mut self, index: usize) {
let table = self.get_underlying_table();
table.remove(index);