feat: added rerender when new screenshot is taken (#745)
This commit is contained in:
parent
f2ecde8927
commit
795d80870b
7 changed files with 176 additions and 7 deletions
77
Cargo.lock
generated
77
Cargo.lock
generated
|
|
@ -2416,6 +2416,15 @@ version = "1.3.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
|
||||
|
||||
[[package]]
|
||||
name = "fsevent-sys"
|
||||
version = "4.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.1.31"
|
||||
|
|
@ -3221,6 +3230,26 @@ dependencies = [
|
|||
"web-time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inotify"
|
||||
version = "0.11.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4cc00ea907cab49550b7da656f80ebb97be1b997d931fbcd28d39734e17ce592"
|
||||
dependencies = [
|
||||
"bitflags 2.13.1",
|
||||
"inotify-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inotify-sys"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c033f80b2c113cdf91ab7a33faa9cbc014726dcad99880c8609af2a370edf37d"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "interfrost"
|
||||
version = "1.3.2"
|
||||
|
|
@ -3407,6 +3436,26 @@ version = "3.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc"
|
||||
|
||||
[[package]]
|
||||
name = "kqueue"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d763e5b24120b4ddf50de6c92308156765aabfbbccebf401da7cff2d70a41ea"
|
||||
dependencies = [
|
||||
"kqueue-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kqueue-sys"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "07293a4e297ac234359b510362495713f75ea345d5307140414f20c69ffeb087"
|
||||
dependencies = [
|
||||
"bitflags 2.13.1",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "language-tags"
|
||||
version = "0.3.2"
|
||||
|
|
@ -3844,6 +3893,33 @@ version = "0.3.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8"
|
||||
|
||||
[[package]]
|
||||
name = "notify"
|
||||
version = "8.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4d3d07927151ff8575b7087f245456e549fea62edf0ec4e565a5ee50c8402bc3"
|
||||
dependencies = [
|
||||
"bitflags 2.13.1",
|
||||
"fsevent-sys",
|
||||
"inotify",
|
||||
"kqueue",
|
||||
"libc",
|
||||
"log",
|
||||
"mio",
|
||||
"notify-types",
|
||||
"walkdir",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "notify-types"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42b8cfee0e339a0337359f3c88165702ac6e600dc01c0cc9579a92d62b08477a"
|
||||
dependencies = [
|
||||
"bitflags 2.13.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ntapi"
|
||||
version = "0.4.3"
|
||||
|
|
@ -4420,6 +4496,7 @@ dependencies = [
|
|||
"freya-skia-safe",
|
||||
"image",
|
||||
"mimalloc",
|
||||
"notify",
|
||||
"oneclient_auth",
|
||||
"oneclient_cluster",
|
||||
"oneclient_common",
|
||||
|
|
|
|||
|
|
@ -113,6 +113,7 @@ dunce = {version = "=1.0.5"}
|
|||
htmd = {version = "=0.5.4"}
|
||||
indicatif = {version = "=0.18.4", features = ["tokio"]}
|
||||
junction = {version = "=2.0.0"}
|
||||
notify = {version = "=8.2.0"}
|
||||
parking_lot = {version = "=0.12.5"}
|
||||
rand = {version = "=0.10.1"}
|
||||
regex = {version = "=1.12.3"}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,8 @@ uuid.workspace = true
|
|||
bytes.workspace = true
|
||||
sysinfo.workspace = true
|
||||
|
||||
notify.workspace = true
|
||||
|
||||
anyhow.workspace = true
|
||||
regex.workspace = true
|
||||
|
||||
|
|
|
|||
|
|
@ -51,7 +51,8 @@ pub use queries::{
|
|||
use_package_project, use_package_search, use_package_versions, use_package_versions_when,
|
||||
use_player_profile,
|
||||
use_player_skin, use_provider_versions, use_refresh_account, use_refresh_all_accounts,
|
||||
use_remove_account, use_screenshot_action, use_set_default_account, use_terms, use_upload_log,
|
||||
use_remove_account, use_screenshot_action, use_screenshot_folder_watch, use_set_default_account,
|
||||
use_terms, use_upload_log,
|
||||
use_version_metadata, use_versions, version_list, versions_metadata, versions_total,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
use crate::hooks::use_settings_snapshot;
|
||||
|
||||
/// Not the url itself just enough to notice when the meta host setting
|
||||
/// changes so a different host refetches instead of serving the old answer
|
||||
fn use_meta_url_key() -> String {
|
||||
use_settings_snapshot()
|
||||
.settings
|
||||
|
|
@ -88,7 +86,7 @@ pub use packages::{
|
|||
pub use player_profile::use_player_profile;
|
||||
pub use screenshots::{
|
||||
ScreenshotAction, UseScreenshotAction, invalidate_screenshots_queries, try_cluster_screenshots,
|
||||
use_cluster_screenshots, use_local_image, use_screenshot_action,
|
||||
use_cluster_screenshots, use_local_image, use_screenshot_action, use_screenshot_folder_watch,
|
||||
};
|
||||
pub use settings_profiles::{
|
||||
try_game_profile, use_cluster_profile, use_cluster_settings, use_game_profile,
|
||||
|
|
|
|||
|
|
@ -1,13 +1,17 @@
|
|||
use std::path::PathBuf;
|
||||
use std::ffi::OsStr;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::{Arc, OnceLock};
|
||||
use std::time::Duration;
|
||||
|
||||
use bytes::Bytes;
|
||||
use freya::prelude::{spawn, use_hook};
|
||||
use freya::query::{
|
||||
Mutation, MutationCapability, QueriesStorage, Query, QueryCapability,
|
||||
UseMutation, UseQuery, use_mutation, use_query,
|
||||
};
|
||||
use notify::{EventKind, RecursiveMode, Watcher};
|
||||
use oneclient_core::{LauncherError, ScreenshotInfo};
|
||||
use tokio::sync::Semaphore;
|
||||
use tokio::sync::{Semaphore, mpsc};
|
||||
|
||||
static LOCAL_IMAGE_SEMAPHORE: OnceLock<Arc<Semaphore>> = OnceLock::new();
|
||||
|
||||
|
|
@ -84,6 +88,90 @@ pub fn use_local_image(path: PathBuf, max_edge: u32) -> UseQuery<LocalImageQuery
|
|||
))
|
||||
}
|
||||
|
||||
const WATCH_QUIET: Duration = Duration::from_millis(400);
|
||||
|
||||
pub fn use_screenshot_folder_watch(
|
||||
folder: Option<PathBuf>,
|
||||
query: UseQuery<ClusterScreenshotsQuery>,
|
||||
) {
|
||||
use_hook(move || {
|
||||
let Some(folder) = folder else {
|
||||
return;
|
||||
};
|
||||
|
||||
spawn(async move {
|
||||
if let Err(err) = watch_folder(&folder, query).await {
|
||||
tracing::warn!(
|
||||
folder = %folder.display(),
|
||||
error = %err,
|
||||
"not watching the screenshot folder; the list will refresh on re-entry only"
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async fn watch_folder(
|
||||
folder: &Path,
|
||||
query: UseQuery<ClusterScreenshotsQuery>,
|
||||
) -> notify::Result<()> {
|
||||
// If there is no screenshots folder it creates it
|
||||
std::fs::create_dir_all(folder)?;
|
||||
|
||||
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||
let mut watcher = notify::recommended_watcher(move |event: notify::Result<notify::Event>| {
|
||||
match event {
|
||||
Ok(event) if touches_image(&event) => {
|
||||
let _ = tx.send(());
|
||||
}
|
||||
Ok(_) => {}
|
||||
Err(err) => tracing::debug!(error = %err, "screenshot watcher reported an error"),
|
||||
}
|
||||
})?;
|
||||
watcher.watch(folder, RecursiveMode::NonRecursive)?;
|
||||
|
||||
let mut pending = false;
|
||||
loop {
|
||||
tokio::select! {
|
||||
biased;
|
||||
|
||||
event = rx.recv() => {
|
||||
if event.is_none() {
|
||||
return Ok(());
|
||||
}
|
||||
pending = true;
|
||||
}
|
||||
|
||||
() = quiet_period(pending) => {
|
||||
pending = false;
|
||||
query.invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn quiet_period(pending: bool) {
|
||||
if pending {
|
||||
tokio::time::sleep(WATCH_QUIET).await;
|
||||
} else {
|
||||
std::future::pending::<()>().await;
|
||||
}
|
||||
}
|
||||
|
||||
fn touches_image(event: ¬ify::Event) -> bool {
|
||||
if matches!(event.kind, EventKind::Access(_)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
event.paths.iter().any(|path| {
|
||||
path.extension().and_then(OsStr::to_str).is_some_and(|ext| {
|
||||
["png", "jpg", "jpeg"]
|
||||
.iter()
|
||||
.any(|known| ext.eq_ignore_ascii_case(known))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub fn try_cluster_screenshots(
|
||||
query: &UseQuery<ClusterScreenshotsQuery>,
|
||||
) -> Option<Vec<ScreenshotInfo>> {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use crate::components::{
|
|||
Button, ContextMenu, Icon, IconType, LocalImage, OverlayPopup, ScreenshotViewer, ScrollArea,
|
||||
Segment, SegmentedControl, open_folder_button,
|
||||
};
|
||||
use crate::hooks::{ScreenshotAction, query_is_loading, try_cluster_screenshots, use_cluster_screenshots, use_dispatch, use_screenshot_action, use_view_state};
|
||||
use crate::hooks::{ScreenshotAction, query_is_loading, try_cluster_screenshots, use_cluster_screenshots, use_dispatch, use_screenshot_action, use_screenshot_folder_watch, use_view_state};
|
||||
use crate::layout::cluster_content;
|
||||
use crate::theme::colors;
|
||||
use crate::ui::{border_all_color, flow_grid, fmt_date, grid_columns_for_width};
|
||||
|
|
@ -39,6 +39,8 @@ impl Component for ClusterScreenshots {
|
|||
let folder = cluster.game_dir().ok().map(|d| d.join("screenshots"));
|
||||
|
||||
let query = use_cluster_screenshots(self.cluster_id);
|
||||
// Otherwise a screenshot taken in game only shows up on the next visit
|
||||
use_screenshot_folder_watch(folder.clone(), query);
|
||||
let action = use_screenshot_action();
|
||||
|
||||
let shots = try_cluster_screenshots(&query).unwrap_or_default();
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue