desktop: Add Open URL option

This commit is contained in:
Mike Welsh 2023-03-28 02:11:09 -07:00 committed by Nathan Adams
parent e5a874065e
commit 5bf43f9025
3 changed files with 72 additions and 12 deletions

View File

@ -11,6 +11,9 @@ pub enum RuffleEvent {
/// The user requested to open a new local SWF.
OpenFile,
/// The user requested to open a URL.
OpenURL(url::Url),
/// The user requested to exit Ruffle.
ExitRequested,

View File

@ -147,9 +147,11 @@ impl GuiController {
pub struct RuffleGui {
event_loop: EventLoopProxy<RuffleEvent>,
esc_start_time: Option<Instant>,
open_url_text: String,
is_esc_down: bool,
is_ui_visible: bool,
is_about_visible: bool,
is_open_url_prompt_visible: bool,
context_menu: Vec<ruffle_core::ContextMenuItem>,
}
@ -158,9 +160,11 @@ impl RuffleGui {
Self {
event_loop,
esc_start_time: None,
open_url_text: String::new(),
is_esc_down: false,
is_ui_visible: false,
is_about_visible: false,
is_open_url_prompt_visible: false,
context_menu: vec![],
}
}
@ -202,6 +206,7 @@ impl RuffleGui {
if self.is_ui_visible {
self.main_menu_bar(egui_ctx);
self.about_window(egui_ctx);
self.open_url_prompt(egui_ctx);
}
if !self.context_menu.is_empty() {
@ -242,13 +247,18 @@ impl RuffleGui {
let mut shortcut;
shortcut = KeyboardShortcut::new(Modifiers::COMMAND, Key::O);
if Button::new("Open...")
if Button::new("Open File...")
.shortcut_text(ui.ctx().format_shortcut(&shortcut))
.ui(ui)
.clicked()
{
self.open_file(ui);
}
if Button::new("Open URL...").ui(ui).clicked() {
self.show_open_url_prompt(ui);
}
ui.separator();
shortcut = KeyboardShortcut::new(Modifiers::COMMAND, Key::Q);
@ -333,6 +343,42 @@ impl RuffleGui {
ui.close_menu();
}
fn open_url_prompt(&mut self, egui_ctx: &egui::Context) {
let mut close_prompt = false;
egui::Window::new("Open URL")
.anchor(Align2::CENTER_CENTER, egui::Vec2::ZERO)
.collapsible(false)
.open(&mut self.is_open_url_prompt_visible)
.show(egui_ctx, |ui| {
ui.vertical_centered(|ui| {
let (enter_pressed, esc_pressed) = ui.ctx().input_mut(|input| {
(
input.consume_key(Modifiers::NONE, Key::Enter),
input.consume_key(Modifiers::NONE, Key::Escape),
)
});
ui.text_edit_singleline(&mut self.open_url_text);
ui.horizontal(|ui| {
if ui.button("OK").clicked() || enter_pressed {
if let Ok(url) = url::Url::parse(&self.open_url_text) {
let _ = self.event_loop.send_event(RuffleEvent::OpenURL(url));
} else {
// TODO: Show error prompt.
tracing::error!("Invalid URL: {}", self.open_url_text);
}
close_prompt = true;
}
if ui.button("Cancel").clicked() || esc_pressed {
close_prompt = true;
}
});
});
});
if close_prompt {
self.is_open_url_prompt_visible = false;
}
}
fn request_exit(&mut self, ui: &mut egui::Ui) {
let _ = self.event_loop.send_event(RuffleEvent::ExitRequested);
ui.close_menu();
@ -348,4 +394,9 @@ impl RuffleGui {
self.is_about_visible = true;
ui.close_menu();
}
fn show_open_url_prompt(&mut self, ui: &mut egui::Ui) {
self.is_open_url_prompt_visible = true;
ui.close_menu();
}
}

View File

@ -327,7 +327,9 @@ impl App {
let (executor, channel) = GlutinAsyncExecutor::new(event_loop.create_proxy());
let navigator = navigator::ExternalNavigatorBackend::new(
opt.base.to_owned().unwrap_or(
movie_url.unwrap_or_else(|| Url::parse("file:///empty").expect("Dummy Url")),
movie_url
.clone()
.unwrap_or_else(|| Url::parse("file:///empty").expect("Dummy Url")),
),
channel,
event_loop.create_proxy(),
@ -403,20 +405,18 @@ impl App {
max_window_size,
};
if let Some(path) = &app.opt.input_path {
app.load_swf(&path.clone())?;
if let Some(movie_url) = movie_url {
app.load_swf(movie_url)?;
}
Ok(app)
}
fn load_swf(&mut self, movie_path: &Path) -> Result<(), Error> {
let movie_url = parse_url(movie_path).context("Couldn't load specified path")?;
let filename = movie_url
fn load_swf(&mut self, url: Url) -> Result<(), Error> {
let filename = url
.path_segments()
.and_then(|segments| segments.last())
.unwrap_or_else(|| movie_url.as_str());
.unwrap_or_else(|| url.as_str());
let title = format!("Ruffle - {filename}");
self.window.set_title(&title);
SWF_INFO.with(|i| *i.borrow_mut() = Some(filename.to_string()));
@ -426,10 +426,10 @@ impl App {
let _ = event_loop_proxy.send_event(RuffleEvent::OnMetadata(swf_header.clone()));
};
let mut parameters: Vec<(String, String)> = movie_url.query_pairs().into_owned().collect();
let mut parameters: Vec<(String, String)> = url.query_pairs().into_owned().collect();
parameters.extend(parse_parameters(&self.opt));
self.player.lock().expect("Player lock").fetch_root_movie(
movie_url.to_string(),
url.to_string(),
parameters,
Box::new(on_metadata),
);
@ -743,11 +743,17 @@ impl App {
winit::event::Event::UserEvent(RuffleEvent::OpenFile) => {
if let Some(path) = pick_file() {
// TODO: Show dialog on error.
let _ = self.load_swf(&path);
let url = parse_url(&path).expect("Couldn't load specified path");
let _ = self.load_swf(url);
self.gui.lock().expect("Gui lock").set_ui_visible(false);
}
}
winit::event::Event::UserEvent(RuffleEvent::OpenURL(url)) => {
let _ = self.load_swf(url);
self.gui.lock().expect("Gui lock").set_ui_visible(false);
}
winit::event::Event::UserEvent(RuffleEvent::ExitRequested) => {
*control_flow = ControlFlow::Exit;
return;