mirror of
https://github.com/djibux/BoilR.git
synced 2026-09-01 05:53:41 +02:00
Update dependencies (#388)
* Upgrade all dependencies, fix image laod * Fix size of import button * Fix size when picking image * Remove unused code * Forgot images when new image selected * Clippy corrections
This commit is contained in:
Generated
+1264
-332
File diff suppressed because it is too large
Load Diff
+8
-7
@@ -6,7 +6,7 @@ version = "1.9.4"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
base64 = "^0.21.0"
|
base64 = "^0.21.0"
|
||||||
config = "^0.13.3"
|
config = "^0.13.3"
|
||||||
copypasta = "^0.8.1"
|
copypasta = "^0.10.0"
|
||||||
flate2 = "^1.0.25"
|
flate2 = "^1.0.25"
|
||||||
is_executable = "^1.0.1"
|
is_executable = "^1.0.1"
|
||||||
nom = "^7.1.1"
|
nom = "^7.1.1"
|
||||||
@@ -15,11 +15,12 @@ serde_json = "^1.0.91"
|
|||||||
|
|
||||||
steam_shortcuts_util = "^1.1.8"
|
steam_shortcuts_util = "^1.1.8"
|
||||||
steamgriddb_api = "^0.3.1"
|
steamgriddb_api = "^0.3.1"
|
||||||
sysinfo = "^0.29.0"
|
sysinfo = "^0.30.5"
|
||||||
eyre = "^0.6.8"
|
eyre = "^0.6.8"
|
||||||
color-eyre = "^0.6.2"
|
color-eyre = "^0.6.2"
|
||||||
dyn-clone = "^1.0.10"
|
dyn-clone = "^1.0.10"
|
||||||
time = {version="^0.3.17", features = ["formatting"]}
|
time = {version="^0.3.17", features = ["formatting"]}
|
||||||
|
egui_extras = { version = "0.25.0", features = ["all_loaders"] }
|
||||||
|
|
||||||
[target."cfg(not(windows))".dependencies]
|
[target."cfg(not(windows))".dependencies]
|
||||||
openssl = { version = "*", features = ["vendored"] }
|
openssl = { version = "*", features = ["vendored"] }
|
||||||
@@ -29,10 +30,10 @@ features = ["serde"]
|
|||||||
version = "^5.4.0"
|
version = "^5.4.0"
|
||||||
|
|
||||||
[dependencies.eframe]
|
[dependencies.eframe]
|
||||||
version = "^0.22.0"
|
version = "^0.25.0"
|
||||||
|
|
||||||
[dependencies.egui]
|
[dependencies.egui]
|
||||||
version = "^0.22.0"
|
version = "^0.25.0"
|
||||||
|
|
||||||
[dependencies.futures]
|
[dependencies.futures]
|
||||||
version = "^0.3.25"
|
version = "^0.3.25"
|
||||||
@@ -62,9 +63,9 @@ version = "^0.8.0"
|
|||||||
winres = "^0.1.12"
|
winres = "^0.1.12"
|
||||||
|
|
||||||
[target."cfg(windows)".dependencies]
|
[target."cfg(windows)".dependencies]
|
||||||
winreg = "^0.51.0"
|
winreg = "^0.52.0"
|
||||||
sqlite = "^0.31.1"
|
sqlite = "^0.32.0"
|
||||||
roxmltree = "^0.18.0"
|
roxmltree = "^0.19.0"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
# This feature is enabled when building for a flatpak environment
|
# This feature is enabled when building for a flatpak environment
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ pub(crate) fn get_egs_manifests(
|
|||||||
|
|
||||||
manifests.sort_by_key(|m| m.dedupe_key());
|
manifests.sort_by_key(|m| m.dedupe_key());
|
||||||
manifests.dedup_by_key(|m| m.dedupe_key());
|
manifests.dedup_by_key(|m| m.dedupe_key());
|
||||||
for mut manifest in &mut manifests {
|
for manifest in &mut manifests {
|
||||||
manifest.launcher_path = Some(locations.launcher_path.clone());
|
manifest.launcher_path = Some(locations.launcher_path.clone());
|
||||||
manifest.compat_folder = locations.compat_folder_path.clone();
|
manifest.compat_folder = locations.compat_folder_path.clone();
|
||||||
if settings.safe_launch.contains(&manifest.display_name)
|
if settings.safe_launch.contains(&manifest.display_name)
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ impl PlaynitePlatform {
|
|||||||
fn get_playnite_games(&self) -> eyre::Result<Vec<PlayniteGame>> {
|
fn get_playnite_games(&self) -> eyre::Result<Vec<PlayniteGame>> {
|
||||||
let mut res = vec![];
|
let mut res = vec![];
|
||||||
let (launcher_path, games_file_path) = self.find_paths()?;
|
let (launcher_path, games_file_path) = self.find_paths()?;
|
||||||
let games_bytes = std::fs::read(&games_file_path).map_err(|e| match e.raw_os_error() {
|
let games_bytes = std::fs::read(games_file_path).map_err(|e| match e.raw_os_error() {
|
||||||
Some(32) => {
|
Some(32) => {
|
||||||
eyre::format_err!("It looks like Playnite is running and preventing BoilR from reading its database, please ensure that Playnite closed.")
|
eyre::format_err!("It looks like Playnite is running and preventing BoilR from reading its database, please ensure that Playnite closed.")
|
||||||
}
|
}
|
||||||
@@ -123,7 +123,6 @@ impl PlaynitePlatform {
|
|||||||
return Err(eyre::eyre!("Did not find Playnite installation"));
|
return Err(eyre::eyre!("Did not find Playnite installation"));
|
||||||
}
|
}
|
||||||
let app_data_path = env::var("APPDATA")?;
|
let app_data_path = env::var("APPDATA")?;
|
||||||
let launcher_path = launcher_path;
|
|
||||||
let playnite_folder = Path::new(&app_data_path).join("Playnite");
|
let playnite_folder = Path::new(&app_data_path).join("Playnite");
|
||||||
let games_file_path = playnite_folder.join("library").join("games.db");
|
let games_file_path = playnite_folder.join("library").join("games.db");
|
||||||
Ok((launcher_path, games_file_path))
|
Ok((launcher_path, games_file_path))
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use std::{process::Command, thread::sleep, time::Duration};
|
use std::{process::Command, thread::sleep, time::Duration};
|
||||||
|
|
||||||
use sysinfo::{ProcessExt, System, SystemExt};
|
use sysinfo::System;
|
||||||
|
|
||||||
pub fn ensure_steam_stopped() {
|
pub fn ensure_steam_stopped() {
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
|
|||||||
@@ -69,7 +69,6 @@ pub fn get_shortcuts_paths(settings: &SteamSettings) -> eyre::Result<Vec<SteamUs
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
if !user_data_path.exists() {}
|
|
||||||
let user_folders = std::fs::read_dir(&user_data_path)?;
|
let user_folders = std::fs::read_dir(&user_data_path)?;
|
||||||
let users_info = user_folders
|
let users_info = user_folders
|
||||||
.filter_map(|f| f.ok())
|
.filter_map(|f| f.ok())
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ impl<'a> CachedSearch<'a> {
|
|||||||
}
|
}
|
||||||
println!("Searching for {}", query.as_ref());
|
println!("Searching for {}", query.as_ref());
|
||||||
let search = self.client.search(query.as_ref()).await?;
|
let search = self.client.search(query.as_ref()).await?;
|
||||||
let first_id = search.get(0).map(|f| f.id);
|
let first_id = search.first().map(|f| f.id);
|
||||||
match first_id {
|
match first_id {
|
||||||
Some(assumed_id) => {
|
Some(assumed_id) => {
|
||||||
self.search_map.insert(app_id, (query.into(), assumed_id));
|
self.search_map.insert(app_id, (query.into(), assumed_id));
|
||||||
|
|||||||
@@ -22,16 +22,6 @@ impl ImageType {
|
|||||||
&ALL_TYPES
|
&ALL_TYPES
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ratio(&self) -> f32{
|
|
||||||
match self {
|
|
||||||
ImageType::Hero => 0.3,
|
|
||||||
ImageType::Grid => 1.6,
|
|
||||||
ImageType::WideGrid => 0.5,
|
|
||||||
ImageType::Logo => 0.2,
|
|
||||||
ImageType::BigPicture => 0.5,
|
|
||||||
ImageType::Icon => 1.0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn name(&self) -> &str {
|
pub fn name(&self) -> &str {
|
||||||
match self {
|
match self {
|
||||||
|
|||||||
@@ -1,186 +0,0 @@
|
|||||||
use std::path::{Path, PathBuf};
|
|
||||||
|
|
||||||
use egui::{Button, ImageButton};
|
|
||||||
use futures::executor::block_on;
|
|
||||||
use tokio::runtime::Runtime;
|
|
||||||
|
|
||||||
use crate::steamgriddb::{ToDownload, ImageType};
|
|
||||||
use crate::ui::images::{clamp_to_width, ImageHandles, TextureDownloadState};
|
|
||||||
use crate::ui::ui_images::load_image_from_path;
|
|
||||||
|
|
||||||
pub struct GameButton {
|
|
||||||
path: PathBuf,
|
|
||||||
max_width: f32,
|
|
||||||
text: String,
|
|
||||||
image_type: ImageType,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GameButton {
|
|
||||||
pub fn new(path: &Path) -> Self {
|
|
||||||
Self {
|
|
||||||
max_width: 200.0,
|
|
||||||
path: path.to_path_buf(),
|
|
||||||
text: Default::default(),
|
|
||||||
image_type: ImageType::Grid,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn width(&mut self, max_width: f32) -> &mut Self {
|
|
||||||
self.max_width = max_width;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn text(&mut self, text: &str) -> &mut Self {
|
|
||||||
self.text = text.to_string();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn image_type(&mut self, image_type:&ImageType) -> &mut Self{
|
|
||||||
self.image_type = *image_type;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn show_download(
|
|
||||||
&self,
|
|
||||||
ui: &mut egui::Ui,
|
|
||||||
image_handles: &ImageHandles,
|
|
||||||
rt: &Runtime,
|
|
||||||
url: &str,
|
|
||||||
) -> bool {
|
|
||||||
self.render_possible_image(ui, image_handles, Some(rt), Some(url))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn show(&self, ui: &mut egui::Ui, image_handles: &ImageHandles) -> bool {
|
|
||||||
self.render_possible_image(ui, image_handles, None, None)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render_possible_image(
|
|
||||||
&self,
|
|
||||||
ui: &mut egui::Ui,
|
|
||||||
image_handles: &ImageHandles,
|
|
||||||
rt: Option<&Runtime>,
|
|
||||||
url: Option<&str>,
|
|
||||||
) -> bool {
|
|
||||||
{
|
|
||||||
let path = &self.path;
|
|
||||||
let image_key = path.to_string_lossy().to_string();
|
|
||||||
match image_handles.get_mut(&image_key) {
|
|
||||||
Some(mut state) => {
|
|
||||||
match state.value() {
|
|
||||||
TextureDownloadState::Downloading => {
|
|
||||||
ui.ctx().request_repaint();
|
|
||||||
//nothing to do,just wait
|
|
||||||
ui.spinner();
|
|
||||||
}
|
|
||||||
TextureDownloadState::Downloaded => {
|
|
||||||
//Need to load
|
|
||||||
let image_data = load_image_from_path(path);
|
|
||||||
match image_data {
|
|
||||||
Ok(image_data) => {
|
|
||||||
let handle = ui.ctx().load_texture(
|
|
||||||
&image_key,
|
|
||||||
image_data,
|
|
||||||
egui::TextureOptions::LINEAR,
|
|
||||||
);
|
|
||||||
*state.value_mut() = TextureDownloadState::Loaded(handle);
|
|
||||||
ui.spinner();
|
|
||||||
}
|
|
||||||
Err(_) => *state.value_mut() = TextureDownloadState::Failed,
|
|
||||||
}
|
|
||||||
ui.ctx().request_repaint();
|
|
||||||
}
|
|
||||||
TextureDownloadState::Loaded(texture_handle) => {
|
|
||||||
//need to show
|
|
||||||
let mut size = texture_handle.size_vec2();
|
|
||||||
clamp_to_width(&mut size, self.max_width);
|
|
||||||
let image_button = ImageButton::new(texture_handle, size);
|
|
||||||
if ui
|
|
||||||
.add_sized(size, image_button)
|
|
||||||
.on_hover_text(&self.text)
|
|
||||||
.clicked()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TextureDownloadState::Failed => {
|
|
||||||
let button = ui.add_sized(
|
|
||||||
[self.max_width, self.max_width * self.image_type.ratio()],
|
|
||||||
Button::new(&self.text).wrap(true),
|
|
||||||
);
|
|
||||||
if button.clicked() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
match url {
|
|
||||||
Some(url) => {
|
|
||||||
download_image(
|
|
||||||
path,
|
|
||||||
image_handles,
|
|
||||||
&image_key,
|
|
||||||
url,
|
|
||||||
&self.image_type,
|
|
||||||
rt,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
//Not possible to download
|
|
||||||
if !path.exists() {
|
|
||||||
image_handles.insert(image_key, TextureDownloadState::Failed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Default for GameButton {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::new(Path::new(""))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fn download_image(
|
|
||||||
path: &Path,
|
|
||||||
image_handles: &ImageHandles,
|
|
||||||
image_key: &str,
|
|
||||||
url: &str,
|
|
||||||
image_type: &ImageType,
|
|
||||||
rt: Option<&Runtime>,
|
|
||||||
) {
|
|
||||||
//We need to start a download
|
|
||||||
//Redownload if file is too small
|
|
||||||
if !path.exists() || std::fs::metadata(path).map(|m| m.len()).unwrap_or_default() < 2 {
|
|
||||||
image_handles.insert(image_key.to_string(), TextureDownloadState::Downloading);
|
|
||||||
let to_download = ToDownload {
|
|
||||||
path: path.to_path_buf(),
|
|
||||||
url: url.to_string(),
|
|
||||||
app_name: "Thumbnail".to_string(),
|
|
||||||
image_type: *image_type,
|
|
||||||
};
|
|
||||||
let image_handles = image_handles.clone();
|
|
||||||
let image_key = image_key.to_string();
|
|
||||||
if let Some(rt) = rt {
|
|
||||||
rt.spawn_blocking(move || {
|
|
||||||
match block_on(crate::steamgriddb::download_to_download(&to_download)) {
|
|
||||||
Ok(_) => {
|
|
||||||
image_handles.insert(image_key, TextureDownloadState::Downloaded);
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
println!(
|
|
||||||
"Failed downloading image {} error: {:?}",
|
|
||||||
to_download.url, err
|
|
||||||
);
|
|
||||||
image_handles.insert(image_key, TextureDownloadState::Failed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
image_handles.insert(image_key.to_string(), TextureDownloadState::Downloaded);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
mod steam_user_select;
|
mod steam_user_select;
|
||||||
mod game_image_button;
|
|
||||||
|
|
||||||
pub use steam_user_select::render_user_select;
|
pub use steam_user_select::render_user_select;
|
||||||
pub use game_image_button::GameButton;
|
|
||||||
@@ -26,6 +26,6 @@ pub fn render_user_select<'a>(
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return steam_users.get(0);
|
return steam_users.first();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-80
@@ -12,28 +12,11 @@ pub mod ui_colors {
|
|||||||
|
|
||||||
pub mod ui_images {
|
pub mod ui_images {
|
||||||
|
|
||||||
use std::thread::JoinHandle;
|
|
||||||
|
|
||||||
use eframe::IconData;
|
use egui::IconData;
|
||||||
use egui::{ColorImage, ImageData};
|
|
||||||
|
|
||||||
pub const IMPORT_GAMES_IMAGE: &[u8] = include_bytes!("../../resources/import_games_button.png");
|
|
||||||
pub const SAVE_IMAGE: &[u8] = include_bytes!("../../resources/save.png");
|
|
||||||
pub const LOGO_32: &[u8] = include_bytes!("../../resources/logo32.png");
|
|
||||||
pub const LOGO_ICON: &[u8] = include_bytes!("../../resources/logo_small.png");
|
pub const LOGO_ICON: &[u8] = include_bytes!("../../resources/logo_small.png");
|
||||||
|
|
||||||
pub fn get_import_image() -> ImageData {
|
|
||||||
ImageData::Color(load_image_from_memory(IMPORT_GAMES_IMAGE).unwrap_or_default())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_save_image() -> ImageData {
|
|
||||||
ImageData::Color(load_image_from_memory(SAVE_IMAGE).unwrap_or_default())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_logo() -> ImageData {
|
|
||||||
ImageData::Color(load_image_from_memory(LOGO_32).unwrap_or_default())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_logo_icon() -> IconData {
|
pub fn get_logo_icon() -> IconData {
|
||||||
let image = image::load_from_memory(LOGO_ICON).unwrap_or_default();
|
let image = image::load_from_memory(LOGO_ICON).unwrap_or_default();
|
||||||
let image_buffer = image.to_rgba8();
|
let image_buffer = image.to_rgba8();
|
||||||
@@ -45,66 +28,4 @@ pub mod ui_images {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_image_from_path(path: &std::path::Path) -> eyre::Result<egui::ColorImage> {
|
|
||||||
let path_owned = path.to_owned();
|
|
||||||
let handle: JoinHandle<eyre::Result<egui::ColorImage>> = std::thread::spawn(move || {
|
|
||||||
let image = image::io::Reader::open(path_owned)?
|
|
||||||
.with_guessed_format()?
|
|
||||||
.decode()?;
|
|
||||||
let size = [image.width() as _, image.height() as _];
|
|
||||||
let image_buffer = image.to_rgba8();
|
|
||||||
let pixels = image_buffer.as_flat_samples();
|
|
||||||
Ok(egui::ColorImage::from_rgba_unmultiplied(
|
|
||||||
size,
|
|
||||||
pixels.as_slice(),
|
|
||||||
))
|
|
||||||
});
|
|
||||||
match handle.join() {
|
|
||||||
Ok(thread_result) => thread_result,
|
|
||||||
Err(_e) => Err(eyre::format_err!("Failed to load image at {:?} ", path)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn load_image_from_memory(image_data: &[u8]) -> Result<ColorImage, image::ImageError> {
|
|
||||||
let image = image::load_from_memory(image_data)?;
|
|
||||||
let size = [image.width() as _, image.height() as _];
|
|
||||||
let image_buffer = image.to_rgba8();
|
|
||||||
let pixels = image_buffer.as_flat_samples();
|
|
||||||
Ok(ColorImage::from_rgba_unmultiplied(size, pixels.as_slice()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::ui_images::load_image_from_path;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_image_load_that_is_broken() {
|
|
||||||
let res = load_image_from_path(std::path::Path::new("src/testdata/brokenimage.webp"));
|
|
||||||
assert!(res.is_err());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_image_load_that_works_png() {
|
|
||||||
let res = load_image_from_path(std::path::Path::new("src/testdata/smallpng.png"));
|
|
||||||
assert!(res.is_ok());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_image_load_that_works_webp() {
|
|
||||||
let res = load_image_from_path(std::path::Path::new("src/testdata/spider.webp"));
|
|
||||||
assert!(res.is_ok());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_image_load_animated_webp() {
|
|
||||||
let res = load_image_from_path(std::path::Path::new("src/testdata/hollow.webp"));
|
|
||||||
assert!(res.is_err());
|
|
||||||
}
|
|
||||||
|
|
||||||
// #[test]
|
|
||||||
// pub fn test_image_load_animated_webp2() {
|
|
||||||
// let res = load_image_from_path(std::path::Path::new("src/testdata/tunic.webp"));
|
|
||||||
// assert!(res.is_err());
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
pub fn clamp_to_width(size: &mut egui::Vec2, max_width: f32) {
|
|
||||||
let mut x = size.x;
|
|
||||||
let mut y = size.y;
|
|
||||||
if size.x > max_width {
|
|
||||||
let ratio = size.y / size.x;
|
|
||||||
x = max_width;
|
|
||||||
y = x * ratio;
|
|
||||||
}
|
|
||||||
size.x = x;
|
|
||||||
size.y = y;
|
|
||||||
}
|
|
||||||
@@ -1,15 +1,12 @@
|
|||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use steam_shortcuts_util::shortcut::ShortcutOwned;
|
use steam_shortcuts_util::shortcut::ShortcutOwned;
|
||||||
|
|
||||||
use dashmap::DashMap;
|
|
||||||
use crate::{steam::SteamUsersInfo, steamgriddb::ImageType, ui::FetcStatus};
|
use crate::{steam::SteamUsersInfo, steamgriddb::ImageType, ui::FetcStatus};
|
||||||
|
|
||||||
use super::{ gamemode::GameMode, possible_image::PossibleImage, texturestate::TextureDownloadState, gametype::GameType};
|
use super::{ gamemode::GameMode, possible_image::PossibleImage, gametype::GameType};
|
||||||
|
|
||||||
use tokio::sync::watch::{self, Receiver};
|
use tokio::sync::watch::{self, Receiver};
|
||||||
|
|
||||||
pub type ImageHandles = std::sync::Arc<DashMap<String, TextureDownloadState>>;
|
|
||||||
|
|
||||||
pub struct ImageSelectState {
|
pub struct ImageSelectState {
|
||||||
pub selected_shortcut: Option<GameType>,
|
pub selected_shortcut: Option<GameType>,
|
||||||
@@ -23,7 +20,6 @@ pub struct ImageSelectState {
|
|||||||
pub image_type_selected: Option<ImageType>,
|
pub image_type_selected: Option<ImageType>,
|
||||||
pub image_options: Receiver<FetcStatus<Vec<PossibleImage>>>,
|
pub image_options: Receiver<FetcStatus<Vec<PossibleImage>>>,
|
||||||
pub steam_games: Option<Vec<crate::steam::SteamGameInfo>>,
|
pub steam_games: Option<Vec<crate::steam::SteamGameInfo>>,
|
||||||
pub image_handles: ImageHandles,
|
|
||||||
|
|
||||||
pub possible_names: Option<Vec<steamgriddb_api::search::SearchResult>>,
|
pub possible_names: Option<Vec<steamgriddb_api::search::SearchResult>>,
|
||||||
}
|
}
|
||||||
@@ -43,7 +39,6 @@ impl Default for ImageSelectState {
|
|||||||
image_type_selected: Default::default(),
|
image_type_selected: Default::default(),
|
||||||
possible_names: None,
|
possible_names: None,
|
||||||
image_options: watch::channel(FetcStatus::NeedsFetched).1,
|
image_options: watch::channel(FetcStatus::NeedsFetched).1,
|
||||||
image_handles: Arc::new(DashMap::new()),
|
|
||||||
steam_games: None,
|
steam_games: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
mod texturestate;
|
|
||||||
mod ui_image_download;
|
mod ui_image_download;
|
||||||
mod gamemode;
|
mod gamemode;
|
||||||
mod possible_image;
|
mod possible_image;
|
||||||
@@ -6,12 +5,8 @@ mod image_select_state;
|
|||||||
mod gametype;
|
mod gametype;
|
||||||
mod useraction;
|
mod useraction;
|
||||||
mod hasimagekey;
|
mod hasimagekey;
|
||||||
mod image_resize;
|
|
||||||
mod constants;
|
mod constants;
|
||||||
|
|
||||||
mod pages;
|
mod pages;
|
||||||
|
|
||||||
pub use image_select_state::ImageSelectState;
|
pub use image_select_state::ImageSelectState;
|
||||||
pub use image_select_state::ImageHandles;
|
|
||||||
pub use texturestate::TextureDownloadState;
|
|
||||||
pub use image_resize::clamp_to_width;
|
|
||||||
@@ -1,13 +1,12 @@
|
|||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use egui::Grid;
|
use egui::{Grid, ImageButton};
|
||||||
use futures::executor::block_on;
|
use futures::executor::block_on;
|
||||||
use tokio::sync::watch;
|
use tokio::sync::watch;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
steamgriddb::{get_image_extension, ImageType, ToDownload},
|
steamgriddb::{get_image_extension, ImageType, ToDownload},
|
||||||
ui::{
|
ui::{
|
||||||
components::GameButton,
|
|
||||||
images::{
|
images::{
|
||||||
constants::MAX_WIDTH, hasimagekey::HasImageKey, image_select_state::ImageSelectState,
|
constants::MAX_WIDTH, hasimagekey::HasImageKey, image_select_state::ImageSelectState,
|
||||||
possible_image::PossibleImage, useraction::UserAction,
|
possible_image::PossibleImage, useraction::UserAction,
|
||||||
@@ -17,7 +16,6 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub fn render_page_pick_image(
|
pub fn render_page_pick_image(
|
||||||
app: &MyEguiApp,
|
|
||||||
ui: &mut egui::Ui,
|
ui: &mut egui::Ui,
|
||||||
image_type: &ImageType,
|
image_type: &ImageType,
|
||||||
state: &ImageSelectState,
|
state: &ImageSelectState,
|
||||||
@@ -57,13 +55,24 @@ pub fn render_page_pick_image(
|
|||||||
let x = Grid::new("ImageThumbnailSelectGrid")
|
let x = Grid::new("ImageThumbnailSelectGrid")
|
||||||
.spacing([column_padding, column_padding])
|
.spacing([column_padding, column_padding])
|
||||||
.show(ui, |ui| {
|
.show(ui, |ui| {
|
||||||
for image in images {
|
for possible_image in images {
|
||||||
let path = image.thumbnail_path.as_path();
|
let image = egui::Image::new(&possible_image.thumbnail_url)
|
||||||
let mut button = GameButton::new(path);
|
.max_width(column_width)
|
||||||
button.width(column_width);
|
.shrink_to_fit();
|
||||||
button.text("Pick image");
|
let calced = image.calc_size(
|
||||||
if button.show_download(ui, &state.image_handles, &app.rt,&image.thumbnail_url) {
|
egui::Vec2 {
|
||||||
return Some(image.clone());
|
x: column_width,
|
||||||
|
y: f32::INFINITY,
|
||||||
|
},
|
||||||
|
image.size(),
|
||||||
|
);
|
||||||
|
let button = ImageButton::new(image);
|
||||||
|
let clicked = ui
|
||||||
|
.add_sized(calced, button)
|
||||||
|
.on_hover_text("Pick image")
|
||||||
|
.clicked();
|
||||||
|
if clicked {
|
||||||
|
return Some(possible_image);
|
||||||
}
|
}
|
||||||
column += 1;
|
column += 1;
|
||||||
if column >= columns {
|
if column >= columns {
|
||||||
@@ -75,7 +84,7 @@ pub fn render_page_pick_image(
|
|||||||
})
|
})
|
||||||
.inner;
|
.inner;
|
||||||
if let Some(x) = x {
|
if let Some(x) = x {
|
||||||
return Some(UserAction::ImageSelected(x));
|
return Some(UserAction::ImageSelected(x.clone()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@@ -106,23 +115,6 @@ pub fn handle_image_selected(app: &mut MyEguiApp, image: PossibleImage) {
|
|||||||
|
|
||||||
delete_images_of_type(user, selected_shortcut, selected_image_type);
|
delete_images_of_type(user, selected_shortcut, selected_image_type);
|
||||||
|
|
||||||
//Put the loaded thumbnail into the image handler map, we can use that for preview
|
|
||||||
let full_image_key = to_download_to_path.to_string_lossy().to_string();
|
|
||||||
let _ = app
|
|
||||||
.image_selected_state
|
|
||||||
.image_handles
|
|
||||||
.remove(&full_image_key);
|
|
||||||
let thumbnail_key = image.thumbnail_path.to_string_lossy().to_string();
|
|
||||||
let thumbnail = app
|
|
||||||
.image_selected_state
|
|
||||||
.image_handles
|
|
||||||
.remove(&thumbnail_key);
|
|
||||||
if let Some((_key, thumbnail)) = thumbnail {
|
|
||||||
app.image_selected_state
|
|
||||||
.image_handles
|
|
||||||
.insert(full_image_key, thumbnail);
|
|
||||||
}
|
|
||||||
|
|
||||||
let app_name = selected_shortcut.name();
|
let app_name = selected_shortcut.name();
|
||||||
let to_download = ToDownload {
|
let to_download = ToDownload {
|
||||||
path: to_download_to_path,
|
path: to_download_to_path,
|
||||||
@@ -134,7 +126,6 @@ pub fn handle_image_selected(app: &mut MyEguiApp, image: PossibleImage) {
|
|||||||
let _ = block_on(crate::steamgriddb::download_to_download(&to_download));
|
let _ = block_on(crate::steamgriddb::download_to_download(&to_download));
|
||||||
});
|
});
|
||||||
|
|
||||||
clear_loaded_images(app);
|
|
||||||
{
|
{
|
||||||
app.image_selected_state.image_type_selected = None;
|
app.image_selected_state.image_type_selected = None;
|
||||||
app.image_selected_state.image_options = watch::channel(FetcStatus::NeedsFetched).1;
|
app.image_selected_state.image_options = watch::channel(FetcStatus::NeedsFetched).1;
|
||||||
@@ -164,12 +155,3 @@ fn image_path(
|
|||||||
) -> PathBuf {
|
) -> PathBuf {
|
||||||
selected_shortcut.key(selected_image_type, data_folder).0
|
selected_shortcut.key(selected_image_type, data_folder).0
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear_loaded_images(app: &mut MyEguiApp) {
|
|
||||||
if let FetcStatus::Fetched(options) = &*app.image_selected_state.image_options.borrow() {
|
|
||||||
for option in options {
|
|
||||||
let key = option.thumbnail_path.to_string_lossy().to_string();
|
|
||||||
app.image_selected_state.image_handles.remove(&key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use crate::ui::components::GameButton;
|
use egui::ImageButton;
|
||||||
|
|
||||||
use crate::ui::images::{
|
use crate::ui::images::{
|
||||||
gametype::GameType, hasimagekey::HasImageKey, image_select_state::ImageSelectState,
|
gametype::GameType, hasimagekey::HasImageKey, image_select_state::ImageSelectState,
|
||||||
useraction::UserAction, ImageHandles,
|
useraction::UserAction,
|
||||||
};
|
};
|
||||||
use crate::{steamgriddb::ImageType};
|
use crate::steamgriddb::ImageType;
|
||||||
|
|
||||||
const MAX_WIDTH: f32 = 300.;
|
const MAX_WIDTH: f32 = 300.;
|
||||||
|
|
||||||
@@ -20,7 +21,7 @@ pub fn render_page_shortcut_select_image_type(
|
|||||||
.map(|user| &user.steam_user_data_folder);
|
.map(|user| &user.steam_user_data_folder);
|
||||||
if let (Some(shortcut), Some(user_path)) = (shortcut, user_path) {
|
if let (Some(shortcut), Some(user_path)) = (shortcut, user_path) {
|
||||||
let thumbnail = |ui: &mut egui::Ui, image_type: &ImageType| {
|
let thumbnail = |ui: &mut egui::Ui, image_type: &ImageType| {
|
||||||
if render_thumbnail(ui, &state.image_handles, shortcut, image_type, user_path) {
|
if render_thumbnail(ui, shortcut, image_type, user_path) {
|
||||||
Some(UserAction::ImageTypeSelected(*image_type))
|
Some(UserAction::ImageTypeSelected(*image_type))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
@@ -76,17 +77,14 @@ pub fn render_page_shortcut_select_image_type(
|
|||||||
|
|
||||||
fn render_thumbnail(
|
fn render_thumbnail(
|
||||||
ui: &mut egui::Ui,
|
ui: &mut egui::Ui,
|
||||||
image_handles: &ImageHandles,
|
|
||||||
shortcut: &GameType,
|
shortcut: &GameType,
|
||||||
image_type: &ImageType,
|
image_type: &ImageType,
|
||||||
user_path: &String,
|
user_path: &String,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let (path, _key) = shortcut.key(image_type, Path::new(&user_path));
|
let (_path, key) = shortcut.key(image_type, Path::new(&user_path));
|
||||||
let text = format!("Pick {} image", image_type.name());
|
let text = format!("Pick {} image", image_type.name());
|
||||||
let mut image = GameButton::new(&path);
|
let image = egui::Image::new(format!("file://{}", key)).max_width(MAX_WIDTH).shrink_to_fit();
|
||||||
image
|
let calced = image.calc_size(egui::Vec2 { x: MAX_WIDTH, y: f32::INFINITY }, image.size());
|
||||||
.width(MAX_WIDTH)
|
let button = ImageButton::new(image);
|
||||||
.text(&text)
|
ui.add_sized(calced,button).on_hover_text(text).clicked()
|
||||||
.image_type(image_type)
|
|
||||||
.show(ui, image_handles)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
|
use egui::ImageButton;
|
||||||
use steam_shortcuts_util::shortcut::ShortcutOwned;
|
use steam_shortcuts_util::shortcut::ShortcutOwned;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@@ -7,11 +8,10 @@ use crate::{
|
|||||||
steamgriddb::{CachedSearch, ImageType},
|
steamgriddb::{CachedSearch, ImageType},
|
||||||
ui::{
|
ui::{
|
||||||
images::{
|
images::{
|
||||||
gametype::GameType, hasimagekey::HasImageKey, texturestate::TextureDownloadState,
|
gametype::GameType, hasimagekey::HasImageKey,
|
||||||
useraction::UserAction,
|
useraction::UserAction,
|
||||||
},
|
},
|
||||||
ui_images::load_image_from_path,
|
MyEguiApp,
|
||||||
MyEguiApp, components::GameButton,
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ pub fn render_page_shortcut_images_overview(
|
|||||||
if let Some(action) = egui::Grid::new("ui_images")
|
if let Some(action) = egui::Grid::new("ui_images")
|
||||||
.show(ui, |ui| {
|
.show(ui, |ui| {
|
||||||
for shortcut in shortcuts {
|
for shortcut in shortcuts {
|
||||||
let action = render_image(app, shortcut, user_info, column_width, ui);
|
let action = render_image(shortcut, user_info, column_width, ui);
|
||||||
if action.is_some() {
|
if action.is_some() {
|
||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
@@ -57,7 +57,6 @@ pub fn render_page_shortcut_images_overview(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn render_image(
|
fn render_image(
|
||||||
app: &MyEguiApp,
|
|
||||||
shortcut: &ShortcutOwned,
|
shortcut: &ShortcutOwned,
|
||||||
user_info: &SteamUsersInfo,
|
user_info: &SteamUsersInfo,
|
||||||
column_width: f32,
|
column_width: f32,
|
||||||
@@ -67,22 +66,20 @@ fn render_image(
|
|||||||
&ImageType::Grid,
|
&ImageType::Grid,
|
||||||
Path::new(&user_info.steam_user_data_folder),
|
Path::new(&user_info.steam_user_data_folder),
|
||||||
);
|
);
|
||||||
|
let image = egui::Image::new(format!("file://{}", key)).max_width(column_width).shrink_to_fit();
|
||||||
|
let calced = image.calc_size(egui::Vec2 { x: column_width, y: f32::INFINITY }, image.size());
|
||||||
|
let button = ImageButton::new(image);
|
||||||
|
|
||||||
let mut button = GameButton::new(Path::new(&key));
|
if ui.add_sized(calced,button).on_hover_text(&shortcut.app_name).clicked() {
|
||||||
button.text(&shortcut.app_name);
|
|
||||||
button.width(column_width);
|
|
||||||
let clicked = button.show(ui, &app.image_selected_state.image_handles);
|
|
||||||
if clicked {
|
|
||||||
return Some(Some(UserAction::ShortcutSelected(GameType::Shortcut(
|
return Some(Some(UserAction::ShortcutSelected(GameType::Shortcut(
|
||||||
Box::new(shortcut.clone()),
|
Box::new(shortcut.clone()),
|
||||||
))));
|
))));
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
pub fn handle_shortcut_selected(app: &mut MyEguiApp, shortcut: GameType, ui: &mut egui::Ui) {
|
pub fn handle_shortcut_selected(app: &mut MyEguiApp, shortcut: GameType ) {
|
||||||
let state = &mut app.image_selected_state;
|
let state = &mut app.image_selected_state;
|
||||||
//We must have a user to make see this action;
|
//We must have a user to get to this action;
|
||||||
if let Some(user) = state.steam_user.as_ref() {
|
|
||||||
if let Some(auth_key) = &app.settings.steamgrid_db.auth_key {
|
if let Some(auth_key) = &app.settings.steamgrid_db.auth_key {
|
||||||
let client = steamgriddb_api::Client::new(auth_key);
|
let client = steamgriddb_api::Client::new(auth_key);
|
||||||
let search = CachedSearch::new(&client);
|
let search = CachedSearch::new(&client);
|
||||||
@@ -92,20 +89,5 @@ pub fn handle_shortcut_selected(app: &mut MyEguiApp, shortcut: GameType, ui: &mu
|
|||||||
.ok()
|
.ok()
|
||||||
.flatten();
|
.flatten();
|
||||||
}
|
}
|
||||||
state.selected_shortcut = Some(shortcut.clone());
|
|
||||||
|
|
||||||
for image_type in ImageType::all() {
|
|
||||||
let (path, key) = shortcut.key(image_type, Path::new(&user.steam_user_data_folder));
|
|
||||||
let image = load_image_from_path(&path);
|
|
||||||
if let Ok(image) = image {
|
|
||||||
let texture = ui
|
|
||||||
.ctx()
|
|
||||||
.load_texture(&key, image, egui::TextureOptions::LINEAR);
|
|
||||||
state
|
|
||||||
.image_handles
|
|
||||||
.insert(key, TextureDownloadState::Loaded(texture));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
state.selected_shortcut = Some(shortcut);
|
state.selected_shortcut = Some(shortcut);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
#[derive(Clone)]
|
|
||||||
pub enum TextureDownloadState {
|
|
||||||
Downloading,
|
|
||||||
Downloaded,
|
|
||||||
Loaded(egui::TextureHandle),
|
|
||||||
Failed,
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
use super::{
|
use super::{
|
||||||
constants::POSSIBLE_EXTENSIONS,
|
constants::POSSIBLE_EXTENSIONS,
|
||||||
gamemode::GameMode,
|
gamemode::GameMode,
|
||||||
hasimagekey::HasImageKey,
|
|
||||||
image_select_state::ImageSelectState,
|
image_select_state::ImageSelectState,
|
||||||
pages::{
|
pages::{
|
||||||
handle_correct_grid_request, handle_grid_change, handle_image_selected,
|
handle_correct_grid_request, handle_grid_change, handle_image_selected,
|
||||||
@@ -9,11 +8,10 @@ use super::{
|
|||||||
render_page_shortcut_select_image_type, render_page_steam_images_overview,
|
render_page_shortcut_select_image_type, render_page_steam_images_overview,
|
||||||
},
|
},
|
||||||
possible_image::PossibleImage,
|
possible_image::PossibleImage,
|
||||||
texturestate::TextureDownloadState,
|
|
||||||
useraction::UserAction,
|
useraction::UserAction,
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::path::Path;
|
use std::{ path::Path, thread, time::Duration};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::get_thumbnails_folder,
|
config::get_thumbnails_folder,
|
||||||
@@ -21,7 +19,7 @@ use crate::{
|
|||||||
steam::{get_installed_games, SteamUsersInfo},
|
steam::{get_installed_games, SteamUsersInfo},
|
||||||
steamgriddb::{get_image_extension, get_query_type, ImageType},
|
steamgriddb::{get_image_extension, get_query_type, ImageType},
|
||||||
sync::{download_images, SyncProgress},
|
sync::{download_images, SyncProgress},
|
||||||
ui::{components::render_user_select, ui_images::load_image_from_path, FetcStatus, MyEguiApp},
|
ui::{components::render_user_select, FetcStatus, MyEguiApp},
|
||||||
};
|
};
|
||||||
use egui::ScrollArea;
|
use egui::ScrollArea;
|
||||||
use futures::executor::block_on;
|
use futures::executor::block_on;
|
||||||
@@ -67,7 +65,7 @@ impl MyEguiApp {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
} else if let Some(image_type) = state.image_type_selected.as_ref() {
|
} else if let Some(image_type) = state.image_type_selected.as_ref() {
|
||||||
if let Some(action) = render_page_pick_image(self, ui, image_type, state) {
|
if let Some(action) = render_page_pick_image(ui, image_type, state) {
|
||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
} else if let Some(action) = render_page_shortcut_select_image_type(ui, state) {
|
} else if let Some(action) = render_page_shortcut_select_image_type(ui, state) {
|
||||||
@@ -148,16 +146,18 @@ impl MyEguiApp {
|
|||||||
});
|
});
|
||||||
match action {
|
match action {
|
||||||
UserAction::UserSelected(user) => {
|
UserAction::UserSelected(user) => {
|
||||||
self.handle_user_selected(user, ui);
|
self.handle_user_selected(user);
|
||||||
}
|
}
|
||||||
UserAction::ShortcutSelected(shortcut) => {
|
UserAction::ShortcutSelected(shortcut) => {
|
||||||
handle_shortcut_selected(self, shortcut, ui);
|
handle_shortcut_selected(self, shortcut);
|
||||||
}
|
}
|
||||||
UserAction::ImageTypeSelected(image_type) => {
|
UserAction::ImageTypeSelected(image_type) => {
|
||||||
self.handle_image_type_selected(image_type);
|
self.handle_image_type_selected(image_type);
|
||||||
}
|
}
|
||||||
UserAction::ImageSelected(image) => {
|
UserAction::ImageSelected(image) => {
|
||||||
handle_image_selected(self, image);
|
handle_image_selected(self, image);
|
||||||
|
thread::sleep(Duration::from_millis(100));
|
||||||
|
ui.ctx().forget_all_images();
|
||||||
}
|
}
|
||||||
UserAction::BackButton => {
|
UserAction::BackButton => {
|
||||||
self.handle_back_button_action();
|
self.handle_back_button_action();
|
||||||
@@ -173,21 +173,23 @@ impl MyEguiApp {
|
|||||||
handle_correct_grid_request(self);
|
handle_correct_grid_request(self);
|
||||||
}
|
}
|
||||||
UserAction::ImageTypeCleared(image_type, should_ban) => {
|
UserAction::ImageTypeCleared(image_type, should_ban) => {
|
||||||
self.handle_image_type_cleared(image_type, should_ban)
|
self.handle_image_type_cleared(image_type, should_ban);
|
||||||
|
ui.ctx().forget_all_images();
|
||||||
}
|
}
|
||||||
UserAction::ClearImages => {
|
UserAction::ClearImages => {
|
||||||
self.handle_clear_all_images();
|
self.handle_clear_all_images();
|
||||||
|
ui.ctx().forget_all_images();
|
||||||
}
|
}
|
||||||
UserAction::DownloadAllImages => {
|
UserAction::DownloadAllImages => {
|
||||||
self.handle_download_all_images();
|
self.handle_download_all_images();
|
||||||
|
ui.ctx().forget_all_images();
|
||||||
}
|
}
|
||||||
UserAction::RefreshImages => {
|
UserAction::RefreshImages => {
|
||||||
let (_, reciever) = watch::channel(SyncProgress::NotStarted);
|
|
||||||
let user = self.image_selected_state.steam_user.clone();
|
let user = self.image_selected_state.steam_user.clone();
|
||||||
if let Some(user) = &user {
|
if let Some(user) = &user {
|
||||||
load_image_grids(user, &mut self.image_selected_state, ui);
|
load_image_grids(user);
|
||||||
}
|
}
|
||||||
self.status_reciever = reciever;
|
ui.ctx().forget_all_images();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -252,8 +254,6 @@ impl MyEguiApp {
|
|||||||
if path.exists() {
|
if path.exists() {
|
||||||
let _ = std::fs::remove_file(&path);
|
let _ = std::fs::remove_file(&path);
|
||||||
}
|
}
|
||||||
let key = path.to_string_lossy().to_string();
|
|
||||||
self.image_selected_state.image_handles.remove(&key);
|
|
||||||
}
|
}
|
||||||
self.image_selected_state.image_type_selected = None;
|
self.image_selected_state.image_type_selected = None;
|
||||||
}
|
}
|
||||||
@@ -264,9 +264,9 @@ impl MyEguiApp {
|
|||||||
self.image_selected_state.steam_games = Some(get_installed_games(&self.settings.steam));
|
self.image_selected_state.steam_games = Some(get_installed_games(&self.settings.steam));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_user_selected(&mut self, user: SteamUsersInfo, ui: &mut egui::Ui) {
|
fn handle_user_selected(&mut self, user: SteamUsersInfo) {
|
||||||
let state = &mut self.image_selected_state;
|
let state = &mut self.image_selected_state;
|
||||||
let shortcuts = load_image_grids(&user, state, ui);
|
let shortcuts = load_image_grids(&user);
|
||||||
state.user_shortcuts = Some(shortcuts);
|
state.user_shortcuts = Some(shortcuts);
|
||||||
state.steam_user = Some(user);
|
state.steam_user = Some(user);
|
||||||
}
|
}
|
||||||
@@ -279,8 +279,6 @@ impl MyEguiApp {
|
|||||||
let settings = self.settings.clone();
|
let settings = self.settings.clone();
|
||||||
if let Some(auth_key) = settings.steamgrid_db.auth_key {
|
if let Some(auth_key) = settings.steamgrid_db.auth_key {
|
||||||
if let Some(grid_id) = self.image_selected_state.grid_id {
|
if let Some(grid_id) = self.image_selected_state.grid_id {
|
||||||
let auth_key = auth_key;
|
|
||||||
let image_type = image_type;
|
|
||||||
self.rt.spawn_blocking(move || {
|
self.rt.spawn_blocking(move || {
|
||||||
let thumbnails_folder = get_thumbnails_folder();
|
let thumbnails_folder = get_thumbnails_folder();
|
||||||
let client = steamgriddb_api::Client::new(auth_key);
|
let client = steamgriddb_api::Client::new(auth_key);
|
||||||
@@ -316,18 +314,14 @@ impl MyEguiApp {
|
|||||||
} else if state.selected_shortcut.is_some() {
|
} else if state.selected_shortcut.is_some() {
|
||||||
state.selected_shortcut = None;
|
state.selected_shortcut = None;
|
||||||
} else {
|
} else {
|
||||||
state.image_handles.clear();
|
|
||||||
state.user_shortcuts = None;
|
state.user_shortcuts = None;
|
||||||
state.steam_user = None;
|
state.steam_user = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_image_grids(
|
//TODO remove this
|
||||||
user: &SteamUsersInfo,
|
fn load_image_grids(user: &SteamUsersInfo) -> Vec<ShortcutOwned> {
|
||||||
state: &mut ImageSelectState,
|
|
||||||
ui: &mut egui::Ui,
|
|
||||||
) -> Vec<ShortcutOwned> {
|
|
||||||
let user_info = crate::steam::get_shortcuts_for_user(user);
|
let user_info = crate::steam::get_shortcuts_for_user(user);
|
||||||
match user_info {
|
match user_info {
|
||||||
Ok(user_info) => {
|
Ok(user_info) => {
|
||||||
@@ -336,22 +330,6 @@ fn load_image_grids(
|
|||||||
user_folder.pop();
|
user_folder.pop();
|
||||||
let mut shortcuts = user_info.shortcuts;
|
let mut shortcuts = user_info.shortcuts;
|
||||||
shortcuts.sort_by_key(|s| s.app_name.clone());
|
shortcuts.sort_by_key(|s| s.app_name.clone());
|
||||||
let image_type = &ImageType::Grid;
|
|
||||||
for shortcut in &shortcuts {
|
|
||||||
let (path, key) = shortcut.key(image_type, &user_folder);
|
|
||||||
let loaded = state.image_handles.contains_key(&key);
|
|
||||||
if !loaded && path.exists() {
|
|
||||||
let image = load_image_from_path(&path);
|
|
||||||
if let Ok(image) = image {
|
|
||||||
let texture =
|
|
||||||
ui.ctx()
|
|
||||||
.load_texture(&key, image, egui::TextureOptions::LINEAR);
|
|
||||||
state
|
|
||||||
.image_handles
|
|
||||||
.insert(key, TextureDownloadState::Loaded(texture));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
shortcuts
|
shortcuts
|
||||||
}
|
}
|
||||||
Err(_err) => {
|
Err(_err) => {
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ impl MyEguiApp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn set_scroll_style(ui: &mut egui::Ui) {
|
fn set_scroll_style(ui: &mut egui::Ui) {
|
||||||
let mut scroll_style = ui.style_mut();
|
let scroll_style = ui.style_mut();
|
||||||
scroll_style.visuals.extreme_bg_color = BACKGROUND_COLOR;
|
scroll_style.visuals.extreme_bg_color = BACKGROUND_COLOR;
|
||||||
scroll_style.visuals.widgets.inactive.bg_fill = EXTRA_BACKGROUND_COLOR;
|
scroll_style.visuals.widgets.inactive.bg_fill = EXTRA_BACKGROUND_COLOR;
|
||||||
scroll_style.visuals.widgets.active.bg_fill = EXTRA_BACKGROUND_COLOR;
|
scroll_style.visuals.widgets.active.bg_fill = EXTRA_BACKGROUND_COLOR;
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ impl MyEguiApp {
|
|||||||
pub(crate) fn render_import_games(&mut self, ui: &mut egui::Ui) {
|
pub(crate) fn render_import_games(&mut self, ui: &mut egui::Ui) {
|
||||||
ui.heading("Import Games");
|
ui.heading("Import Games");
|
||||||
|
|
||||||
let mut scroll_style = ui.style_mut();
|
let scroll_style = ui.style_mut();
|
||||||
scroll_style.visuals.extreme_bg_color = BACKGROUND_COLOR;
|
scroll_style.visuals.extreme_bg_color = BACKGROUND_COLOR;
|
||||||
scroll_style.visuals.widgets.inactive.bg_fill = EXTRA_BACKGROUND_COLOR;
|
scroll_style.visuals.widgets.inactive.bg_fill = EXTRA_BACKGROUND_COLOR;
|
||||||
scroll_style.visuals.widgets.active.bg_fill = EXTRA_BACKGROUND_COLOR;
|
scroll_style.visuals.widgets.active.bg_fill = EXTRA_BACKGROUND_COLOR;
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ impl MyEguiApp {
|
|||||||
pub(crate) fn render_settings(&mut self, ui: &mut egui::Ui) {
|
pub(crate) fn render_settings(&mut self, ui: &mut egui::Ui) {
|
||||||
ui.heading("Settings");
|
ui.heading("Settings");
|
||||||
|
|
||||||
let mut scroll_style = ui.style_mut();
|
let scroll_style = ui.style_mut();
|
||||||
scroll_style.visuals.extreme_bg_color = BACKGROUND_COLOR;
|
scroll_style.visuals.extreme_bg_color = BACKGROUND_COLOR;
|
||||||
scroll_style.visuals.widgets.inactive.bg_fill = EXTRA_BACKGROUND_COLOR;
|
scroll_style.visuals.widgets.inactive.bg_fill = EXTRA_BACKGROUND_COLOR;
|
||||||
scroll_style.visuals.widgets.active.bg_fill = EXTRA_BACKGROUND_COLOR;
|
scroll_style.visuals.widgets.active.bg_fill = EXTRA_BACKGROUND_COLOR;
|
||||||
|
|||||||
+26
-58
@@ -1,7 +1,9 @@
|
|||||||
use std::{collections::HashMap, error::Error, time::Duration};
|
use std::{collections::HashMap, error::Error, time::Duration};
|
||||||
|
|
||||||
use eframe::{egui, App, Frame};
|
use eframe::{egui, App, Frame};
|
||||||
use egui::{ImageButton, Rounding, Stroke, TextureHandle};
|
use egui::{
|
||||||
|
ImageButton, Rounding, Stroke, Vec2
|
||||||
|
};
|
||||||
use tokio::{
|
use tokio::{
|
||||||
runtime::Runtime,
|
runtime::Runtime,
|
||||||
sync::watch::{self, Receiver},
|
sync::watch::{self, Receiver},
|
||||||
@@ -20,19 +22,14 @@ use super::{
|
|||||||
BACKGROUND_COLOR, BG_STROKE_COLOR, EXTRA_BACKGROUND_COLOR, LIGHT_ORANGE, ORANGE, PURLPLE,
|
BACKGROUND_COLOR, BG_STROKE_COLOR, EXTRA_BACKGROUND_COLOR, LIGHT_ORANGE, ORANGE, PURLPLE,
|
||||||
TEXT_COLOR,
|
TEXT_COLOR,
|
||||||
},
|
},
|
||||||
ui_images::{get_import_image, get_logo, get_logo_icon, get_save_image},
|
ui_images::get_logo_icon,
|
||||||
ui_import_games::FetcStatus,
|
ui_import_games::FetcStatus,
|
||||||
BackupState, DiconnectState,
|
BackupState, DiconnectState,
|
||||||
};
|
};
|
||||||
|
|
||||||
const SECTION_SPACING: f32 = 25.0;
|
const SECTION_SPACING: f32 = 25.0;
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
struct UiImages {
|
|
||||||
import_button: Option<egui::TextureHandle>,
|
|
||||||
save_button: Option<egui::TextureHandle>,
|
|
||||||
logo_32: Option<egui::TextureHandle>,
|
|
||||||
}
|
|
||||||
type GamesToSync = Vec<(
|
type GamesToSync = Vec<(
|
||||||
String,
|
String,
|
||||||
Receiver<FetcStatus<eyre::Result<Vec<ShortcutToImport>>>>,
|
Receiver<FetcStatus<eyre::Result<Vec<ShortcutToImport>>>>,
|
||||||
@@ -59,7 +56,6 @@ pub struct MyEguiApp {
|
|||||||
selected_menu: Menues,
|
selected_menu: Menues,
|
||||||
pub(crate) settings: Settings,
|
pub(crate) settings: Settings,
|
||||||
pub(crate) rt: Runtime,
|
pub(crate) rt: Runtime,
|
||||||
ui_images: UiImages,
|
|
||||||
pub(crate) games_to_sync: GamesToSync,
|
pub(crate) games_to_sync: GamesToSync,
|
||||||
pub(crate) status_reciever: Receiver<SyncProgress>,
|
pub(crate) status_reciever: Receiver<SyncProgress>,
|
||||||
pub(crate) image_selected_state: ImageSelectState,
|
pub(crate) image_selected_state: ImageSelectState,
|
||||||
@@ -81,7 +77,6 @@ impl MyEguiApp {
|
|||||||
settings,
|
settings,
|
||||||
rt: runtime,
|
rt: runtime,
|
||||||
games_to_sync,
|
games_to_sync,
|
||||||
ui_images: UiImages::default(),
|
|
||||||
status_reciever: watch::channel(SyncProgress::NotStarted).1,
|
status_reciever: watch::channel(SyncProgress::NotStarted).1,
|
||||||
image_selected_state: ImageSelectState::default(),
|
image_selected_state: ImageSelectState::default(),
|
||||||
backup_state: BackupState::default(),
|
backup_state: BackupState::default(),
|
||||||
@@ -119,12 +114,12 @@ impl MyEguiApp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
let all_ready = all_ready(&self.games_to_sync);
|
let all_ready = all_ready(&self.games_to_sync);
|
||||||
let texture = self.get_import_image(ui);
|
let import_image = egui::include_image!("../../resources/import_games_button.png");
|
||||||
let size = texture.size_vec2();
|
let size = Vec2::new(200.,100.);
|
||||||
let image_button = ImageButton::new(texture, size * 0.40);
|
let image_button = ImageButton::new(import_image);
|
||||||
if all_ready && !syncing {
|
if all_ready && !syncing {
|
||||||
if ui
|
if ui
|
||||||
.add(image_button)
|
.add_sized(size,image_button)
|
||||||
.on_hover_text("Import your games into steam")
|
.on_hover_text("Import your games into steam")
|
||||||
.clicked()
|
.clicked()
|
||||||
{
|
{
|
||||||
@@ -134,7 +129,7 @@ impl MyEguiApp {
|
|||||||
self.run_sync_async();
|
self.run_sync_async();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ui.add(image_button)
|
ui.add_sized(size,image_button)
|
||||||
.on_hover_text("Waiting for sync to finish");
|
.on_hover_text("Waiting for sync to finish");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -187,9 +182,8 @@ impl App for MyEguiApp {
|
|||||||
.default_width(40.0)
|
.default_width(40.0)
|
||||||
.frame(frame)
|
.frame(frame)
|
||||||
.show(ctx, |ui| {
|
.show(ctx, |ui| {
|
||||||
let texture = self.get_logo_image(ui);
|
let image = egui::include_image!("../../resources/logo32.png");
|
||||||
let size = texture.size_vec2();
|
ui.image(image);
|
||||||
ui.image(texture, size);
|
|
||||||
ui.add_space(SECTION_SPACING);
|
ui.add_space(SECTION_SPACING);
|
||||||
|
|
||||||
let menu_before = self.selected_menu.clone();
|
let menu_before = self.selected_menu.clone();
|
||||||
@@ -258,11 +252,14 @@ impl App for MyEguiApp {
|
|||||||
egui::TopBottomPanel::new(egui::panel::TopBottomSide::Bottom, "Bottom Panel")
|
egui::TopBottomPanel::new(egui::panel::TopBottomSide::Bottom, "Bottom Panel")
|
||||||
.frame(frame)
|
.frame(frame)
|
||||||
.show(ctx, |ui| {
|
.show(ctx, |ui| {
|
||||||
let texture = self.get_save_image(ui);
|
let image = egui::include_image!("../../resources/save.png");
|
||||||
let size = texture.size_vec2();
|
let size = image.texture_size().unwrap_or_default();
|
||||||
let save_button = ImageButton::new(texture, size * 0.5);
|
let save_button = ImageButton::new(image);
|
||||||
|
if ui
|
||||||
if ui.add(save_button).on_hover_text("Save settings").clicked() {
|
.add_sized(size * 0.5, save_button)
|
||||||
|
.on_hover_text("Save settings")
|
||||||
|
.clicked()
|
||||||
|
{
|
||||||
if let Err(err) = save_settings(&self.settings, &self.platforms) {
|
if let Err(err) = save_settings(&self.settings, &self.platforms) {
|
||||||
eprintln!("Failed to save settings: {err:?}");
|
eprintln!("Failed to save settings: {err:?}");
|
||||||
}
|
}
|
||||||
@@ -303,36 +300,6 @@ fn create_style(style: &mut egui::Style) {
|
|||||||
style.visuals.widgets.hovered.fg_stroke = Stroke::new(2.0, LIGHT_ORANGE);
|
style.visuals.widgets.hovered.fg_stroke = Stroke::new(2.0, LIGHT_ORANGE);
|
||||||
style.visuals.selection.bg_fill = PURLPLE;
|
style.visuals.selection.bg_fill = PURLPLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MyEguiApp {
|
|
||||||
fn get_import_image(&mut self, ui: &mut egui::Ui) -> &mut TextureHandle {
|
|
||||||
self.ui_images.import_button.get_or_insert_with(|| {
|
|
||||||
// Load the texture only once.
|
|
||||||
ui.ctx().load_texture(
|
|
||||||
"import_image",
|
|
||||||
get_import_image(),
|
|
||||||
egui::TextureOptions::LINEAR,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_save_image(&mut self, ui: &mut egui::Ui) -> &mut TextureHandle {
|
|
||||||
self.ui_images.save_button.get_or_insert_with(|| {
|
|
||||||
// Load the texture only once.
|
|
||||||
ui.ctx()
|
|
||||||
.load_texture("save_image", get_save_image(), egui::TextureOptions::LINEAR)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_logo_image(&mut self, ui: &mut egui::Ui) -> &mut TextureHandle {
|
|
||||||
self.ui_images.logo_32.get_or_insert_with(|| {
|
|
||||||
// Load the texture only once.
|
|
||||||
ui.ctx()
|
|
||||||
.load_texture("logo32", get_logo(), egui::TextureOptions::LINEAR)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn setup(ctx: &egui::Context) {
|
fn setup(ctx: &egui::Context) {
|
||||||
#[cfg(target_family = "unix")]
|
#[cfg(target_family = "unix")]
|
||||||
ctx.set_pixels_per_point(0.999);
|
ctx.set_pixels_per_point(0.999);
|
||||||
@@ -340,6 +307,7 @@ fn setup(ctx: &egui::Context) {
|
|||||||
let mut style: egui::Style = (*ctx.style()).clone();
|
let mut style: egui::Style = (*ctx.style()).clone();
|
||||||
create_style(&mut style);
|
create_style(&mut style);
|
||||||
ctx.set_style(style);
|
ctx.set_style(style);
|
||||||
|
egui_extras::install_image_loaders(ctx);
|
||||||
}
|
}
|
||||||
pub fn run_sync() -> eyre::Result<()> {
|
pub fn run_sync() -> eyre::Result<()> {
|
||||||
let mut app = MyEguiApp::new()?;
|
let mut app = MyEguiApp::new()?;
|
||||||
@@ -354,11 +322,10 @@ pub fn run_ui(args: Vec<String>) -> eyre::Result<()>{
|
|||||||
let app = MyEguiApp::new()?;
|
let app = MyEguiApp::new()?;
|
||||||
let no_v_sync = args.contains(&"--no-vsync".to_string());
|
let no_v_sync = args.contains(&"--no-vsync".to_string());
|
||||||
let fullscreen = is_fullscreen(&args);
|
let fullscreen = is_fullscreen(&args);
|
||||||
|
let logo = get_logo_icon();
|
||||||
|
let viewport = egui::ViewportBuilder { fullscreen: Some(fullscreen), icon: Some(logo.into()), ..Default::default() };
|
||||||
let native_options = eframe::NativeOptions {
|
let native_options = eframe::NativeOptions {
|
||||||
fullscreen,
|
viewport,
|
||||||
maximized: true,
|
|
||||||
//initial_window_size: Some(egui::Vec2 { x: 1280., y: 800. }),
|
|
||||||
icon_data: Some(get_logo_icon()),
|
|
||||||
vsync: !no_v_sync,
|
vsync: !no_v_sync,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
@@ -368,7 +335,8 @@ pub fn run_ui(args: Vec<String>) -> eyre::Result<()>{
|
|||||||
Box::new(|cc| {
|
Box::new(|cc| {
|
||||||
setup(&cc.egui_ctx);
|
setup(&cc.egui_ctx);
|
||||||
Box::new(app)
|
Box::new(app)
|
||||||
}));
|
}),
|
||||||
|
);
|
||||||
run_result.map_err(|e| eyre::eyre!("Could not initialize: {:?}", e))
|
run_result.map_err(|e| eyre::eyre!("Could not initialize: {:?}", e))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user