desktop: add UI for bookmarks
This commit is contained in:
parent
0b7b9eb0a1
commit
e1f9b5e5df
|
@ -530,6 +530,10 @@ impl Player {
|
|||
self.audio.set_volume(volume)
|
||||
}
|
||||
|
||||
pub fn swf(&self) -> Arc<SwfMovie> {
|
||||
self.swf.clone()
|
||||
}
|
||||
|
||||
pub fn prepare_context_menu(&mut self) -> Vec<ContextMenuItem> {
|
||||
self.mutate_with_update_context(|context| {
|
||||
if !context.stage.show_menu() {
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
bookmarks-dialog = Manage Bookmarks
|
|
@ -2,4 +2,5 @@ language-name = English (United States)
|
|||
|
||||
start = Start
|
||||
browse = Browse
|
||||
save = Save
|
||||
save = Save
|
||||
remove = Remove
|
|
@ -27,6 +27,10 @@ help-menu-sponsor-development = Sponsor Development...
|
|||
help-menu-translate-ruffle = Translate Ruffle...
|
||||
help-menu-about = About Ruffle
|
||||
|
||||
bookmarks-menu = Bookmarks
|
||||
bookmarks-menu-add = Add
|
||||
bookmarks-menu-manage = Manage Bookmarks...
|
||||
|
||||
debug-menu = Debug Tools
|
||||
debug-menu-open-stage = View Stage Info
|
||||
debug-menu-open-movie = View Movie
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
mod bookmarks_dialog;
|
||||
mod context_menu;
|
||||
mod controller;
|
||||
mod movie;
|
||||
|
@ -7,9 +8,11 @@ mod preferences_dialog;
|
|||
pub use controller::GuiController;
|
||||
pub use movie::MovieView;
|
||||
use std::borrow::Cow;
|
||||
use std::str::FromStr;
|
||||
use url::Url;
|
||||
|
||||
use crate::custom_event::RuffleEvent;
|
||||
use crate::gui::bookmarks_dialog::BookmarksDialog;
|
||||
use crate::gui::context_menu::ContextMenu;
|
||||
use crate::gui::open_dialog::OpenDialog;
|
||||
use crate::gui::preferences_dialog::PreferencesDialog;
|
||||
|
@ -87,6 +90,7 @@ pub struct RuffleGui {
|
|||
context_menu: Option<ContextMenu>,
|
||||
open_dialog: OpenDialog,
|
||||
preferences_dialog: Option<PreferencesDialog>,
|
||||
bookmarks_dialog: Option<BookmarksDialog>,
|
||||
default_player_options: PlayerOptions,
|
||||
currently_opened: Option<(Url, PlayerOptions)>,
|
||||
was_suspended_before_debug: bool,
|
||||
|
@ -114,6 +118,7 @@ impl RuffleGui {
|
|||
event_loop.clone(),
|
||||
),
|
||||
preferences_dialog: None,
|
||||
bookmarks_dialog: None,
|
||||
|
||||
event_loop,
|
||||
default_player_options,
|
||||
|
@ -139,6 +144,7 @@ impl RuffleGui {
|
|||
self.about_window(&locale, egui_ctx);
|
||||
self.open_dialog(&locale, egui_ctx);
|
||||
self.preferences_dialog(&locale, egui_ctx);
|
||||
self.bookmarks_dialog(&locale, egui_ctx);
|
||||
|
||||
if let Some(player) = player {
|
||||
let was_suspended = player.debug_ui().should_suspend_player();
|
||||
|
@ -300,6 +306,48 @@ impl RuffleGui {
|
|||
self.show_volume_screen(ui);
|
||||
}
|
||||
});
|
||||
menu::menu_button(ui, text(locale, "bookmarks-menu"), |ui| {
|
||||
ui.add_enabled_ui(player.is_some(), |ui| {
|
||||
if Button::new(text(locale, "bookmarks-menu-add")).ui(ui).clicked() {
|
||||
ui.close_menu();
|
||||
if let Some(player) = &player {
|
||||
if let Err(e) = self.preferences.write_bookmarks(|writer| {
|
||||
// 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 {
|
||||
url,
|
||||
}),
|
||||
Err(e) => tracing::warn!("Failed to parse SWF url for bookmark: {e}"),
|
||||
};
|
||||
}) {
|
||||
tracing::warn!("Couldn't update bookmarks: {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let mut have_bookmarks = false;
|
||||
|
||||
self.preferences.bookmarks(|bookmarks| {
|
||||
have_bookmarks = !bookmarks.is_empty();
|
||||
|
||||
if have_bookmarks {
|
||||
ui.separator();
|
||||
for bookmark in bookmarks {
|
||||
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| {
|
||||
ui.add_enabled_ui(player.is_some(), |ui| {
|
||||
if Button::new(text(locale, "debug-menu-open-stage")).ui(ui).clicked() {
|
||||
|
@ -512,6 +560,10 @@ impl RuffleGui {
|
|||
self.preferences_dialog = Some(PreferencesDialog::new(self.preferences.clone()));
|
||||
}
|
||||
|
||||
fn open_bookmarks(&mut self) {
|
||||
self.bookmarks_dialog = Some(BookmarksDialog::new(self.preferences.clone()));
|
||||
}
|
||||
|
||||
fn close_movie(&mut self, ui: &mut egui::Ui) {
|
||||
let _ = self.event_loop.send_event(RuffleEvent::CloseFile);
|
||||
self.currently_opened = None;
|
||||
|
@ -546,6 +598,17 @@ impl RuffleGui {
|
|||
}
|
||||
}
|
||||
|
||||
fn bookmarks_dialog(&mut self, locale: &LanguageIdentifier, egui_ctx: &egui::Context) {
|
||||
let keep_open = if let Some(dialog) = &mut self.bookmarks_dialog {
|
||||
dialog.show(locale, egui_ctx)
|
||||
} else {
|
||||
true
|
||||
};
|
||||
if !keep_open {
|
||||
self.bookmarks_dialog = None;
|
||||
}
|
||||
}
|
||||
|
||||
fn request_exit(&mut self, ui: &mut egui::Ui) {
|
||||
let _ = self.event_loop.send_event(RuffleEvent::ExitRequested);
|
||||
ui.close_menu();
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
use crate::gui::text;
|
||||
use crate::preferences::GlobalPreferences;
|
||||
use egui::{Align2, Button, Grid, Widget, Window};
|
||||
use unic_langid::LanguageIdentifier;
|
||||
|
||||
pub struct BookmarksDialog {
|
||||
preferences: GlobalPreferences,
|
||||
}
|
||||
|
||||
impl BookmarksDialog {
|
||||
pub fn new(preferences: GlobalPreferences) -> Self {
|
||||
Self { preferences }
|
||||
}
|
||||
|
||||
pub fn show(&mut self, locale: &LanguageIdentifier, egui_ctx: &egui::Context) -> bool {
|
||||
let mut keep_open = true;
|
||||
let mut should_close = false;
|
||||
|
||||
Window::new(text(locale, "bookmarks-dialog"))
|
||||
.open(&mut keep_open)
|
||||
.anchor(Align2::CENTER_CENTER, egui::Vec2::ZERO)
|
||||
.collapsible(false)
|
||||
.resizable(false)
|
||||
.show(egui_ctx, |ui| {
|
||||
Grid::new("bookmarks-dialog-grid")
|
||||
.num_columns(2)
|
||||
.striped(true)
|
||||
.show(ui, |ui| {
|
||||
enum BookmarkAction {
|
||||
Remove(usize),
|
||||
}
|
||||
|
||||
let mut action = None;
|
||||
|
||||
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() {
|
||||
ui.label(bookmark.url.as_str());
|
||||
|
||||
if Button::new(text(locale, "remove")).ui(ui).clicked() {
|
||||
action = Some(BookmarkAction::Remove(index));
|
||||
}
|
||||
|
||||
ui.end_row();
|
||||
}
|
||||
});
|
||||
|
||||
if let Some(action) = action {
|
||||
if let Err(e) =
|
||||
self.preferences.write_bookmarks(|writer| match action {
|
||||
BookmarkAction::Remove(index) => writer.remove(index),
|
||||
})
|
||||
{
|
||||
tracing::warn!("Couldn't update bookmarks: {e}");
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
keep_open && !should_close
|
||||
}
|
||||
}
|
|
@ -19,14 +19,12 @@ use ruffle_render::backend::RenderBackend;
|
|||
use ruffle_render::quality::StageQuality;
|
||||
use ruffle_render_wgpu::backend::WgpuRenderBackend;
|
||||
use ruffle_render_wgpu::descriptors::Descriptors;
|
||||
use std::borrow::Cow;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::path::PathBuf;
|
||||
use std::rc::Rc;
|
||||
use std::sync::{Arc, Mutex, MutexGuard};
|
||||
use std::time::Duration;
|
||||
use url::Url;
|
||||
use urlencoding::decode;
|
||||
use winit::event_loop::EventLoopProxy;
|
||||
use winit::window::Window;
|
||||
|
||||
|
@ -191,17 +189,11 @@ impl ActivePlayer {
|
|||
.with_avm2_optimizer_enabled(opt.avm2_optimizer_enabled);
|
||||
let player = builder.build();
|
||||
|
||||
let name = movie_url
|
||||
.path_segments()
|
||||
.and_then(|segments| segments.last())
|
||||
.unwrap_or_else(|| movie_url.as_str())
|
||||
.to_string();
|
||||
|
||||
let readable_name = decode(&name).unwrap_or(Cow::Borrowed(&name));
|
||||
let readable_name = crate::util::url_to_readable_name(movie_url);
|
||||
|
||||
window.set_title(&format!("Ruffle - {readable_name}"));
|
||||
|
||||
SWF_INFO.with(|i| *i.borrow_mut() = Some(name.clone()));
|
||||
SWF_INFO.with(|i| *i.borrow_mut() = Some(readable_name.into_owned()));
|
||||
|
||||
let on_metadata = move |swf_header: &ruffle_core::swf::HeaderExt| {
|
||||
let _ = event_loop.send_event(RuffleEvent::OnMetadata(swf_header.clone()));
|
||||
|
|
|
@ -3,6 +3,7 @@ use anyhow::{anyhow, Error};
|
|||
use gilrs::Button;
|
||||
use rfd::FileDialog;
|
||||
use ruffle_core::events::{GamepadButton, KeyCode, TextControlCode};
|
||||
use std::borrow::Cow;
|
||||
use std::path::{Path, PathBuf};
|
||||
use url::Url;
|
||||
use winit::dpi::PhysicalSize;
|
||||
|
@ -232,6 +233,15 @@ pub fn parse_url(path: &Path) -> Result<Url, Error> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn url_to_readable_name(url: &Url) -> Cow<'_, str> {
|
||||
let name = url
|
||||
.path_segments()
|
||||
.and_then(|segments| segments.last())
|
||||
.unwrap_or_else(|| url.as_str());
|
||||
|
||||
urlencoding::decode(name).unwrap_or(Cow::Borrowed(name))
|
||||
}
|
||||
|
||||
fn actually_pick_file(dir: Option<PathBuf>) -> Option<PathBuf> {
|
||||
let mut dialog = FileDialog::new()
|
||||
.add_filter("Flash Files", &["swf", "spl"])
|
||||
|
|
Loading…
Reference in New Issue