mirror of
https://github.com/yuzu-emu/liftinstall.git
synced 2024-11-09 23:08:41 +00:00
feat(ui): migrate UI/Web framework to WRY
This commit is contained in:
parent
0d4022d348
commit
6e7d045794
1153
Cargo.lock
generated
1153
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -9,7 +9,8 @@ description = "An adaptable installer for your application."
|
|||
build = "build.rs"
|
||||
|
||||
[dependencies]
|
||||
web-view = { version = "0.7", features = ["edge"] }
|
||||
anyhow = "^1"
|
||||
wry = "0.12"
|
||||
tinyfiledialogs = "3.8"
|
||||
|
||||
hyper = "0.11.27"
|
||||
|
|
|
@ -16,7 +16,7 @@ pub fn launch(app_name: &str, is_launcher: bool, framework: InstallerFramework)
|
|||
|
||||
let (servers, address) = rest::server::spawn_servers(framework.clone());
|
||||
|
||||
ui::start_ui(app_name, &address, is_launcher);
|
||||
ui::start_ui(app_name, &address, is_launcher).log_expect("Failed to start UI");
|
||||
|
||||
// Explicitly hint that we want the servers instance until here.
|
||||
drop(servers);
|
||||
|
|
|
@ -2,9 +2,16 @@
|
|||
//!
|
||||
//! Provides a web-view UI.
|
||||
|
||||
use web_view::Content;
|
||||
|
||||
use crate::logging::LoggingErrors;
|
||||
use anyhow::Result;
|
||||
use wry::{
|
||||
application::{
|
||||
dpi::LogicalSize,
|
||||
event::{Event, StartCause, WindowEvent},
|
||||
event_loop::{ControlFlow, EventLoop},
|
||||
window::WindowBuilder,
|
||||
},
|
||||
webview::{RpcResponse, WebViewBuilder},
|
||||
};
|
||||
|
||||
use log::Level;
|
||||
|
||||
|
@ -16,55 +23,56 @@ enum CallbackType {
|
|||
}
|
||||
|
||||
/// Starts the main web UI. Will return when UI is closed.
|
||||
pub fn start_ui(app_name: &str, http_address: &str, is_launcher: bool) {
|
||||
pub fn start_ui(app_name: &str, http_address: &str, is_launcher: bool) -> Result<()> {
|
||||
let size = if is_launcher { (600, 300) } else { (1024, 600) };
|
||||
|
||||
info!("Spawning web view instance");
|
||||
|
||||
web_view::builder()
|
||||
.title(&format!("{} Installer", app_name))
|
||||
.content(Content::Url(http_address))
|
||||
.size(size.0, size.1)
|
||||
.resizable(false)
|
||||
.debug(cfg!(debug_assertions))
|
||||
.user_data(())
|
||||
.invoke_handler(|wv, msg| {
|
||||
let mut cb_result = Ok(());
|
||||
let command: CallbackType =
|
||||
serde_json::from_str(msg).log_expect(&format!("Unable to parse string: {:?}", msg));
|
||||
|
||||
debug!("Incoming payload: {:?}", command);
|
||||
|
||||
match command {
|
||||
CallbackType::SelectInstallDir { callback_name } => {
|
||||
let result =
|
||||
tinyfiledialogs::select_folder_dialog("Select a install directory...", "");
|
||||
|
||||
if let Some(new_path) = result {
|
||||
if !new_path.is_empty() {
|
||||
let result = serde_json::to_string(&new_path)
|
||||
.log_expect("Unable to serialize response");
|
||||
let command = format!("window.{}({});", callback_name, result);
|
||||
debug!("Injecting response: {}", command);
|
||||
cb_result = wv.eval(&command);
|
||||
let event_loop = EventLoop::new();
|
||||
let window = WindowBuilder::new()
|
||||
.with_title(format!("{} Installer", app_name))
|
||||
.with_inner_size(LogicalSize::new(size.0, size.1))
|
||||
.with_resizable(false)
|
||||
.build(&event_loop)?;
|
||||
let _webview = WebViewBuilder::new(window)?
|
||||
.with_url(http_address)?
|
||||
.with_rpc_handler(|_, mut event| {
|
||||
debug!("Incoming payload: {:?}", event);
|
||||
match event.method.as_str() {
|
||||
"Test" => (),
|
||||
"Log" => {
|
||||
if let Some(msg) = event.params.take() {
|
||||
if let Ok(msg) = serde_json::from_value::<(String, String)>(msg) {
|
||||
let kind = match msg.0.as_str() {
|
||||
"info" | "log" => Level::Info,
|
||||
"warn" => Level::Warn,
|
||||
_ => Level::Error,
|
||||
};
|
||||
log!(target: "liftinstall::frontend::js", kind, "{}", msg.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
CallbackType::Log { msg, kind } => {
|
||||
let kind = match kind.as_ref() {
|
||||
"info" | "log" => Level::Info,
|
||||
"warn" => Level::Warn,
|
||||
"error" => Level::Error,
|
||||
_ => Level::Error,
|
||||
};
|
||||
|
||||
log!(target: "liftinstall::frontend::js", kind, "{}", msg);
|
||||
"SelectInstallDir" => {
|
||||
let result =
|
||||
tinyfiledialogs::select_folder_dialog("Select a install directory...", "")
|
||||
.and_then(|v| serde_json::to_value(v).ok());
|
||||
return Some(RpcResponse::new_result(event.id, result));
|
||||
}
|
||||
CallbackType::Test {} => {}
|
||||
_ => warn!("Unknown RPC method: {}", event.method),
|
||||
}
|
||||
|
||||
cb_result
|
||||
None
|
||||
})
|
||||
.run()
|
||||
.log_expect("Unable to launch Web UI!");
|
||||
.build()?;
|
||||
|
||||
event_loop.run(move |event, _, control_flow| {
|
||||
*control_flow = ControlFlow::Wait;
|
||||
|
||||
match event {
|
||||
Event::NewEvents(StartCause::Init) => info!("Webview started"),
|
||||
Event::WindowEvent {
|
||||
event: WindowEvent::CloseRequested,
|
||||
..
|
||||
} => *control_flow = ControlFlow::Exit,
|
||||
_ => (),
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#![deny(unsafe_code)]
|
||||
#![deny(missing_docs)]
|
||||
|
||||
extern crate web_view;
|
||||
extern crate wry;
|
||||
|
||||
extern crate futures;
|
||||
extern crate hyper;
|
||||
|
|
|
@ -25,13 +25,8 @@ export const i18n = new VueI18n({
|
|||
function intercept (method) {
|
||||
console[method] = function () {
|
||||
const message = Array.prototype.slice.apply(arguments).join(' ')
|
||||
window.external.invoke(
|
||||
JSON.stringify({
|
||||
Log: {
|
||||
kind: method,
|
||||
msg: message
|
||||
}
|
||||
})
|
||||
window.rpc.notify(
|
||||
'Log', method, message
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -39,9 +34,7 @@ function intercept (method) {
|
|||
// See if we have access to the JSON interface
|
||||
let hasExternalInterface = false
|
||||
try {
|
||||
window.external.invoke(JSON.stringify({
|
||||
Test: {}
|
||||
}))
|
||||
window.rpc.notify('Test')
|
||||
hasExternalInterface = true
|
||||
} catch (e) {
|
||||
console.warn('Running without JSON interface - unexpected behaviour may occur!')
|
||||
|
@ -50,13 +43,8 @@ try {
|
|||
// Overwrite loggers with the logging backend
|
||||
if (hasExternalInterface) {
|
||||
window.onerror = function (msg, url, line) {
|
||||
window.external.invoke(
|
||||
JSON.stringify({
|
||||
Log: {
|
||||
kind: 'error',
|
||||
msg: msg + ' @ ' + url + ':' + line
|
||||
}
|
||||
})
|
||||
window.rpc.notify(
|
||||
'Log', 'error', msg + ' @ ' + url + ':' + line
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -91,12 +79,6 @@ axios.get('/api/attrs').then(function (resp) {
|
|||
console.error(err)
|
||||
})
|
||||
|
||||
function selectFileCallback (name) {
|
||||
app.install_location = name
|
||||
}
|
||||
|
||||
window.selectFileCallback = selectFileCallback
|
||||
|
||||
const app = new Vue({
|
||||
i18n: i18n,
|
||||
router: router,
|
||||
|
|
|
@ -80,7 +80,7 @@ export default {
|
|||
data: function () {
|
||||
return {
|
||||
publicPath: process.env.BASE_URL,
|
||||
advanced: false,
|
||||
advanced: true,
|
||||
repair: false,
|
||||
installDesktopShortcut: true
|
||||
}
|
||||
|
@ -99,11 +99,12 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
select_file: function () {
|
||||
window.external.invoke(JSON.stringify({
|
||||
SelectInstallDir: {
|
||||
callback_name: 'selectFileCallback'
|
||||
const that = this
|
||||
window.rpc.call('SelectInstallDir').then(function (name) {
|
||||
if (name) {
|
||||
that.$root.$data.install_location = name
|
||||
}
|
||||
}))
|
||||
})
|
||||
},
|
||||
show_overwrite_dialog: function (confirmCallback) {
|
||||
this.$buefy.dialog.confirm({
|
||||
|
|
Loading…
Reference in a new issue