Cmd line args, drag&drop, fs event

This commit is contained in:
Vladimir Borisov 2021-07-21 10:38:49 +03:00
parent a905baf3ef
commit 6f1ba7f8a6
5 changed files with 230 additions and 20 deletions

141
Cargo.lock generated
View file

@ -2,6 +2,26 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "ansi_term"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
dependencies = [
"winapi",
]
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi",
]
[[package]]
name = "autocfg"
version = "1.0.1"
@ -26,6 +46,21 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clap"
version = "2.33.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
dependencies = [
"ansi_term",
"atty",
"bitflags",
"strsim",
"textwrap",
"unicode-width",
"vec_map",
]
[[package]]
name = "com"
version = "0.2.0"
@ -72,6 +107,24 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
[[package]]
name = "heck"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
dependencies = [
"unicode-segmentation",
]
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
[[package]]
name = "itoa"
version = "0.4.7"
@ -288,6 +341,30 @@ dependencies = [
"toml",
]
[[package]]
name = "proc-macro-error"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
dependencies = [
"proc-macro-error-attr",
"proc-macro2",
"quote",
"syn",
"version_check",
]
[[package]]
name = "proc-macro-error-attr"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
dependencies = [
"proc-macro2",
"quote",
"version_check",
]
[[package]]
name = "proc-macro2"
version = "1.0.27"
@ -396,6 +473,7 @@ dependencies = [
"once_cell",
"serde",
"serde_json",
"structopt",
"webview2",
"webview2-sys",
"winapi",
@ -411,6 +489,36 @@ dependencies = [
"libm",
]
[[package]]
name = "strsim"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
[[package]]
name = "structopt"
version = "0.3.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69b041cdcb67226aca307e6e7be44c8806423d83e018bd662360a93dabce4d71"
dependencies = [
"clap",
"lazy_static",
"structopt-derive",
]
[[package]]
name = "structopt-derive"
version = "0.4.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7813934aecf5f51a54775e00068c237de98489463968231a51746bbbc03f9c10"
dependencies = [
"heck",
"proc-macro-error",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "syn"
version = "1.0.73"
@ -422,6 +530,15 @@ dependencies = [
"unicode-xid",
]
[[package]]
name = "textwrap"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
dependencies = [
"unicode-width",
]
[[package]]
name = "toml"
version = "0.5.8"
@ -431,12 +548,36 @@ dependencies = [
"serde",
]
[[package]]
name = "unicode-segmentation"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b"
[[package]]
name = "unicode-width"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
[[package]]
name = "unicode-xid"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "vec_map"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
[[package]]
name = "version_check"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
[[package]]
name = "wasm-bindgen"
version = "0.2.74"

View file

@ -14,4 +14,5 @@ webview2 = "0.1.0"
webview2-sys = "0.1.0-beta.1"
mpv = "0.2.3"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
serde_json = "1.0"
structopt = "0.3"

View file

@ -1,8 +1,20 @@
use native_windows_gui::{self as nwg, NativeUi};
use structopt::StructOpt;
mod stremio_app;
use crate::stremio_app::{stremio_server::StremioServer, MainWindow};
const WEB_ENDPOINT: &str = "http://app.strem.io/shell-v4.4/";
#[derive(StructOpt, Debug)]
#[structopt(name = "basic")]
struct Opt {
#[structopt(long)]
development: bool,
#[structopt(long, default_value = WEB_ENDPOINT)]
webui_url: String,
}
fn main() {
// native-windows-gui has some basic high DPI support with the high-dpi
// feature. It supports the "System DPI Awareness" mode, but not the more
@ -14,10 +26,28 @@ fn main() {
nwg::set_dpi_awareness()
};
let streaming_server = StremioServer::new();
let opt = Opt::from_args();
let streaming_server: Option<StremioServer> = if opt.development {
None
} else {
Some(StremioServer::new())
};
let webui_url = if opt.development && opt.webui_url == WEB_ENDPOINT {
"http://localhost:11470".to_string()
} else {
opt.webui_url
};
nwg::init().expect("Failed to init Native Windows GUI");
let _app = MainWindow::build_ui(Default::default()).expect("Failed to build UI");
let _app = MainWindow::build_ui(MainWindow {
webui_url,
..Default::default()
})
.expect("Failed to build UI");
nwg::dispatch_thread_events();
streaming_server.try_kill();
if let Some(streaming_server) = streaming_server {
streaming_server.try_kill();
}
}

View file

@ -43,19 +43,26 @@ struct RPCResponse {
#[derive(Default, NwgUi)]
pub struct MainWindow {
pub webui_url: String,
#[nwg_control(title: "Stremio", flags: "MAIN_WINDOW|VISIBLE")]
#[nwg_events( OnWindowClose: [MainWindow::on_quit], OnInit: [MainWindow::on_init] )]
window: nwg::Window,
#[nwg_events( OnWindowClose: [MainWindow::on_quit], OnInit: [MainWindow::on_init], OnMinMaxInfo: [MainWindow::on_min_max(SELF, EVT_DATA)] )]
pub window: nwg::Window,
#[nwg_partial(parent: window)]
webview: WebView,
pub webview: WebView,
#[nwg_partial(parent: window)]
player: Player,
pub player: Player,
}
impl MainWindow {
const MIN_WIDTH: i32 = 1000;
const MIN_HEIGHT: i32 = 600;
fn on_init(&self) {
self.webview.endpoint.set(self.webui_url.clone()).ok();
let small_side = cmp::min(nwg::Monitor::width(), nwg::Monitor::height()) * 70 / 100;
let dimensions = (small_side * 16 / 9, small_side);
let dimensions = (
cmp::max(small_side * 16 / 9, Self::MIN_WIDTH),
cmp::max(small_side, Self::MIN_HEIGHT),
);
let [total_width, total_height] = [nwg::Monitor::width(), nwg::Monitor::height()];
let x = (total_width - dimensions.0) / 2;
let y = (total_height - dimensions.1) / 2;
@ -93,7 +100,7 @@ impl MainWindow {
web_tx_player.send(resp_json).ok();
} // recv
}); // thread
// read message from WebView
thread::spawn(move || loop {
let rx = web_rx.lock().unwrap();
if let Ok(msg) = rx.recv() {
@ -131,7 +138,12 @@ impl MainWindow {
let resp_json = serde_json::to_string(&args).unwrap();
player_tx.send(resp_json).ok();
} else {
eprintln!("Unsupported command {:?}", args)
match method {
"toggle-fullscreen" => {
println!("full screen toggle requested");
}
_ => eprintln!("Unsupported command {:?}", args),
}
}
}
}
@ -141,6 +153,10 @@ impl MainWindow {
} // recv
}); // thread
}
fn on_min_max(&self, data: &nwg::EventData) {
let data = data.on_min_max();
data.set_min_size(Self::MIN_WIDTH, Self::MIN_HEIGHT);
}
fn on_quit(&self) {
nwg::stop_thread_dispatch();
}

View file

@ -1,5 +1,6 @@
use native_windows_gui::{self as nwg, PartialUi};
use once_cell::unsync::OnceCell;
use serde_json::json;
use std::cell::RefCell;
use std::mem;
use std::rc::Rc;
@ -12,6 +13,7 @@ use winapi::um::winuser::*;
#[derive(Default)]
pub struct WebView {
pub endpoint: Rc<OnceCell<String>>,
controller: Rc<OnceCell<Controller>>,
pub channel: RefCell<Option<(mpsc::Sender<String>, Arc<Mutex<mpsc::Receiver<String>>>)>>,
notice: nwg::Notice,
@ -31,7 +33,9 @@ impl WebView {
controller.put_bounds(rect).ok();
}
controller.put_is_visible(true).ok();
controller.move_focus(webview2::MoveFocusReason::Programmatic).ok();
controller
.move_focus(webview2::MoveFocusReason::Programmatic)
.ok();
}
}
}
@ -42,8 +46,9 @@ impl PartialUi for WebView {
parent: Option<W>,
) -> Result<(), nwg::NwgError> {
let (tx, rx) = mpsc::channel::<String>();
let (tx1, rx1) = mpsc::channel::<String>();
data.channel = RefCell::new(Some((tx, Arc::new(Mutex::new(rx1)))));
let tx_drag_drop = tx.clone();
let (tx_web, rx_web) = mpsc::channel::<String>();
data.channel = RefCell::new(Some((tx, Arc::new(Mutex::new(rx_web)))));
let parent = parent.expect("No parent window").into();
@ -53,6 +58,7 @@ impl PartialUi for WebView {
.build(&mut data.notice)
.ok();
let controller_clone = data.controller.clone();
let endpoint = data.endpoint.clone();
let hwnd = hwnd as *mut HWND__;
let result = webview2::EnvironmentBuilder::new()
.with_additional_browser_arguments("--disable-gpu")
@ -75,11 +81,13 @@ impl PartialUi for WebView {
let webview = controller
.get_webview()
.expect("Cannot obtain webview from controller");
if let Some(endpoint) = endpoint.get() {
if let Err(e) = webview
.navigate(endpoint.as_str()) {
eprintln!("Cannot load WEB UI at '{}': {:?}", &endpoint, e);
};
}
webview
// .navigate("https://www.boyanpetrov.rip/stremio/index.html")
.navigate("http://app.strem.io/shell-v4.4/")
.expect("Cannot load the webUI");
webview
.add_script_to_execute_on_document_created(
r##"
window.qt={webChannelTransport:{send:window.chrome.webview.postMessage}};
@ -89,9 +97,24 @@ impl PartialUi for WebView {
|_| Ok(()),
)
.ok();
let tx_fs = tx_web.clone();
webview.add_web_message_received(move |_w, msg| {
let msg = msg.try_get_web_message_as_string()?;
tx1.send(msg).ok();
tx_web.send(msg).ok();
Ok(())
}).ok();
webview.add_new_window_requested(move |_w, msg| {
let data = json!({
"object": "transport",
"type": 1,
"args": ["dragdrop" ,[msg.get_uri().unwrap()]]
});
tx_drag_drop.send(data.to_string()).ok();
msg.put_handled(true).ok();
Ok(())
}).ok();
webview.add_contains_full_screen_element_changed(move |_w| {
tx_fs.send(r#"{"id":1, "args": ["toggle-fullscreen"]}"#.to_string()).ok();
Ok(())
}).ok();
WebView::resize_to_window_bounds_and_show(Some(&controller), Some(hwnd));
@ -129,7 +152,6 @@ impl PartialUi for WebView {
) {
use nwg::Event as E;
match evt {
E::OnInit => {}
E::OnResize | E::OnWindowMaximize => {
WebView::resize_to_window_bounds_and_show(self.controller.get(), handle.hwnd());
}