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:
Philip Kristoffersen
2024-01-15 20:47:13 +01:00
committed by GitHub
parent cfb912cc7d
commit f09296f1ff
24 changed files with 1372 additions and 838 deletions
Generated
+1264 -332
View File
File diff suppressed because it is too large Load Diff
+8 -7
View File
@@ -6,7 +6,7 @@ version = "1.9.4"
[dependencies]
base64 = "^0.21.0"
config = "^0.13.3"
copypasta = "^0.8.1"
copypasta = "^0.10.0"
flate2 = "^1.0.25"
is_executable = "^1.0.1"
nom = "^7.1.1"
@@ -15,11 +15,12 @@ serde_json = "^1.0.91"
steam_shortcuts_util = "^1.1.8"
steamgriddb_api = "^0.3.1"
sysinfo = "^0.29.0"
sysinfo = "^0.30.5"
eyre = "^0.6.8"
color-eyre = "^0.6.2"
dyn-clone = "^1.0.10"
time = {version="^0.3.17", features = ["formatting"]}
egui_extras = { version = "0.25.0", features = ["all_loaders"] }
[target."cfg(not(windows))".dependencies]
openssl = { version = "*", features = ["vendored"] }
@@ -29,10 +30,10 @@ features = ["serde"]
version = "^5.4.0"
[dependencies.eframe]
version = "^0.22.0"
version = "^0.25.0"
[dependencies.egui]
version = "^0.22.0"
version = "^0.25.0"
[dependencies.futures]
version = "^0.3.25"
@@ -62,9 +63,9 @@ version = "^0.8.0"
winres = "^0.1.12"
[target."cfg(windows)".dependencies]
winreg = "^0.51.0"
sqlite = "^0.31.1"
roxmltree = "^0.18.0"
winreg = "^0.52.0"
sqlite = "^0.32.0"
roxmltree = "^0.19.0"
[features]
# This feature is enabled when building for a flatpak environment
+1 -1
View File
@@ -27,7 +27,7 @@ pub(crate) fn get_egs_manifests(
manifests.sort_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.compat_folder = locations.compat_folder_path.clone();
if settings.safe_launch.contains(&manifest.display_name)
+1 -2
View File
@@ -86,7 +86,7 @@ impl PlaynitePlatform {
fn get_playnite_games(&self) -> eyre::Result<Vec<PlayniteGame>> {
let mut res = vec![];
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) => {
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"));
}
let app_data_path = env::var("APPDATA")?;
let launcher_path = launcher_path;
let playnite_folder = Path::new(&app_data_path).join("Playnite");
let games_file_path = playnite_folder.join("library").join("games.db");
Ok((launcher_path, games_file_path))
+1 -1
View File
@@ -1,6 +1,6 @@
use std::{process::Command, thread::sleep, time::Duration};
use sysinfo::{ProcessExt, System, SystemExt};
use sysinfo::System;
pub fn ensure_steam_stopped() {
#[cfg(target_os = "windows")]
-1
View File
@@ -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 users_info = user_folders
.filter_map(|f| f.ok())
+1 -1
View File
@@ -46,7 +46,7 @@ impl<'a> CachedSearch<'a> {
}
println!("Searching for {}", query.as_ref());
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 {
Some(assumed_id) => {
self.search_map.insert(app_id, (query.into(), assumed_id));
-10
View File
@@ -22,16 +22,6 @@ impl ImageType {
&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 {
match self {
-186
View File
@@ -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);
}
}
-2
View File
@@ -1,5 +1,3 @@
mod steam_user_select;
mod game_image_button;
pub use steam_user_select::render_user_select;
pub use game_image_button::GameButton;
+1 -1
View File
@@ -26,6 +26,6 @@ pub fn render_user_select<'a>(
None
}
} else {
return steam_users.get(0);
return steam_users.first();
}
}
+1 -80
View File
@@ -12,28 +12,11 @@ pub mod ui_colors {
pub mod ui_images {
use std::thread::JoinHandle;
use eframe::IconData;
use egui::{ColorImage, ImageData};
use egui::IconData;
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 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 {
let image = image::load_from_memory(LOGO_ICON).unwrap_or_default();
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());
// }
}
-11
View File
@@ -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 -6
View File
@@ -1,15 +1,12 @@
use std::sync::Arc;
use steam_shortcuts_util::shortcut::ShortcutOwned;
use dashmap::DashMap;
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};
pub type ImageHandles = std::sync::Arc<DashMap<String, TextureDownloadState>>;
pub struct ImageSelectState {
pub selected_shortcut: Option<GameType>,
@@ -23,7 +20,6 @@ pub struct ImageSelectState {
pub image_type_selected: Option<ImageType>,
pub image_options: Receiver<FetcStatus<Vec<PossibleImage>>>,
pub steam_games: Option<Vec<crate::steam::SteamGameInfo>>,
pub image_handles: ImageHandles,
pub possible_names: Option<Vec<steamgriddb_api::search::SearchResult>>,
}
@@ -43,7 +39,6 @@ impl Default for ImageSelectState {
image_type_selected: Default::default(),
possible_names: None,
image_options: watch::channel(FetcStatus::NeedsFetched).1,
image_handles: Arc::new(DashMap::new()),
steam_games: None,
}
}
-5
View File
@@ -1,4 +1,3 @@
mod texturestate;
mod ui_image_download;
mod gamemode;
mod possible_image;
@@ -6,12 +5,8 @@ mod image_select_state;
mod gametype;
mod useraction;
mod hasimagekey;
mod image_resize;
mod constants;
mod pages;
pub use image_select_state::ImageSelectState;
pub use image_select_state::ImageHandles;
pub use texturestate::TextureDownloadState;
pub use image_resize::clamp_to_width;
+20 -38
View File
@@ -1,13 +1,12 @@
use std::path::{Path, PathBuf};
use egui::Grid;
use egui::{Grid, ImageButton};
use futures::executor::block_on;
use tokio::sync::watch;
use crate::{
steamgriddb::{get_image_extension, ImageType, ToDownload},
ui::{
components::GameButton,
images::{
constants::MAX_WIDTH, hasimagekey::HasImageKey, image_select_state::ImageSelectState,
possible_image::PossibleImage, useraction::UserAction,
@@ -17,7 +16,6 @@ use crate::{
};
pub fn render_page_pick_image(
app: &MyEguiApp,
ui: &mut egui::Ui,
image_type: &ImageType,
state: &ImageSelectState,
@@ -57,13 +55,24 @@ pub fn render_page_pick_image(
let x = Grid::new("ImageThumbnailSelectGrid")
.spacing([column_padding, column_padding])
.show(ui, |ui| {
for image in images {
let path = image.thumbnail_path.as_path();
let mut button = GameButton::new(path);
button.width(column_width);
button.text("Pick image");
if button.show_download(ui, &state.image_handles, &app.rt,&image.thumbnail_url) {
return Some(image.clone());
for possible_image in images {
let image = egui::Image::new(&possible_image.thumbnail_url)
.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 clicked = ui
.add_sized(calced, button)
.on_hover_text("Pick image")
.clicked();
if clicked {
return Some(possible_image);
}
column += 1;
if column >= columns {
@@ -75,7 +84,7 @@ pub fn render_page_pick_image(
})
.inner;
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);
//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 to_download = ToDownload {
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));
});
clear_loaded_images(app);
{
app.image_selected_state.image_type_selected = None;
app.image_selected_state.image_options = watch::channel(FetcStatus::NeedsFetched).1;
@@ -164,12 +155,3 @@ fn image_path(
) -> PathBuf {
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);
}
}
}
+10 -12
View File
@@ -1,11 +1,12 @@
use std::path::Path;
use crate::ui::components::GameButton;
use egui::ImageButton;
use crate::ui::images::{
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.;
@@ -20,7 +21,7 @@ pub fn render_page_shortcut_select_image_type(
.map(|user| &user.steam_user_data_folder);
if let (Some(shortcut), Some(user_path)) = (shortcut, user_path) {
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))
} else {
None
@@ -76,17 +77,14 @@ pub fn render_page_shortcut_select_image_type(
fn render_thumbnail(
ui: &mut egui::Ui,
image_handles: &ImageHandles,
shortcut: &GameType,
image_type: &ImageType,
user_path: &String,
) -> 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 mut image = GameButton::new(&path);
image
.width(MAX_WIDTH)
.text(&text)
.image_type(image_type)
.show(ui, image_handles)
let image = egui::Image::new(format!("file://{}", key)).max_width(MAX_WIDTH).shrink_to_fit();
let calced = image.calc_size(egui::Vec2 { x: MAX_WIDTH, y: f32::INFINITY }, image.size());
let button = ImageButton::new(image);
ui.add_sized(calced,button).on_hover_text(text).clicked()
}
+10 -28
View File
@@ -1,5 +1,6 @@
use std::path::Path;
use egui::ImageButton;
use steam_shortcuts_util::shortcut::ShortcutOwned;
use crate::{
@@ -7,11 +8,10 @@ use crate::{
steamgriddb::{CachedSearch, ImageType},
ui::{
images::{
gametype::GameType, hasimagekey::HasImageKey, texturestate::TextureDownloadState,
gametype::GameType, hasimagekey::HasImageKey,
useraction::UserAction,
},
ui_images::load_image_from_path,
MyEguiApp, components::GameButton,
MyEguiApp,
},
};
@@ -31,7 +31,7 @@ pub fn render_page_shortcut_images_overview(
if let Some(action) = egui::Grid::new("ui_images")
.show(ui, |ui| {
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() {
return action;
}
@@ -57,7 +57,6 @@ pub fn render_page_shortcut_images_overview(
}
fn render_image(
app: &MyEguiApp,
shortcut: &ShortcutOwned,
user_info: &SteamUsersInfo,
column_width: f32,
@@ -67,22 +66,20 @@ fn render_image(
&ImageType::Grid,
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));
button.text(&shortcut.app_name);
button.width(column_width);
let clicked = button.show(ui, &app.image_selected_state.image_handles);
if clicked {
if ui.add_sized(calced,button).on_hover_text(&shortcut.app_name).clicked() {
return Some(Some(UserAction::ShortcutSelected(GameType::Shortcut(
Box::new(shortcut.clone()),
))));
}
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;
//We must have a user to make see this action;
if let Some(user) = state.steam_user.as_ref() {
//We must have a user to get to this action;
if let Some(auth_key) = &app.settings.steamgrid_db.auth_key {
let client = steamgriddb_api::Client::new(auth_key);
let search = CachedSearch::new(&client);
@@ -92,20 +89,5 @@ pub fn handle_shortcut_selected(app: &mut MyEguiApp, shortcut: GameType, ui: &mu
.ok()
.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);
}
}
-7
View File
@@ -1,7 +0,0 @@
#[derive(Clone)]
pub enum TextureDownloadState {
Downloading,
Downloaded,
Loaded(egui::TextureHandle),
Failed,
}
+17 -39
View File
@@ -1,7 +1,6 @@
use super::{
constants::POSSIBLE_EXTENSIONS,
gamemode::GameMode,
hasimagekey::HasImageKey,
image_select_state::ImageSelectState,
pages::{
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,
},
possible_image::PossibleImage,
texturestate::TextureDownloadState,
useraction::UserAction,
};
use std::path::Path;
use std::{ path::Path, thread, time::Duration};
use crate::{
config::get_thumbnails_folder,
@@ -21,7 +19,7 @@ use crate::{
steam::{get_installed_games, SteamUsersInfo},
steamgriddb::{get_image_extension, get_query_type, ImageType},
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 futures::executor::block_on;
@@ -67,7 +65,7 @@ impl MyEguiApp {
return value;
}
} 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;
}
} else if let Some(action) = render_page_shortcut_select_image_type(ui, state) {
@@ -148,16 +146,18 @@ impl MyEguiApp {
});
match action {
UserAction::UserSelected(user) => {
self.handle_user_selected(user, ui);
self.handle_user_selected(user);
}
UserAction::ShortcutSelected(shortcut) => {
handle_shortcut_selected(self, shortcut, ui);
handle_shortcut_selected(self, shortcut);
}
UserAction::ImageTypeSelected(image_type) => {
self.handle_image_type_selected(image_type);
}
UserAction::ImageSelected(image) => {
handle_image_selected(self, image);
thread::sleep(Duration::from_millis(100));
ui.ctx().forget_all_images();
}
UserAction::BackButton => {
self.handle_back_button_action();
@@ -173,21 +173,23 @@ impl MyEguiApp {
handle_correct_grid_request(self);
}
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 => {
self.handle_clear_all_images();
ui.ctx().forget_all_images();
}
UserAction::DownloadAllImages => {
self.handle_download_all_images();
ui.ctx().forget_all_images();
}
UserAction::RefreshImages => {
let (_, reciever) = watch::channel(SyncProgress::NotStarted);
let user = self.image_selected_state.steam_user.clone();
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() {
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;
}
@@ -264,9 +264,9 @@ impl MyEguiApp {
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 shortcuts = load_image_grids(&user, state, ui);
let shortcuts = load_image_grids(&user);
state.user_shortcuts = Some(shortcuts);
state.steam_user = Some(user);
}
@@ -279,8 +279,6 @@ impl MyEguiApp {
let settings = self.settings.clone();
if let Some(auth_key) = settings.steamgrid_db.auth_key {
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 || {
let thumbnails_folder = get_thumbnails_folder();
let client = steamgriddb_api::Client::new(auth_key);
@@ -316,18 +314,14 @@ impl MyEguiApp {
} else if state.selected_shortcut.is_some() {
state.selected_shortcut = None;
} else {
state.image_handles.clear();
state.user_shortcuts = None;
state.steam_user = None;
}
}
}
fn load_image_grids(
user: &SteamUsersInfo,
state: &mut ImageSelectState,
ui: &mut egui::Ui,
) -> Vec<ShortcutOwned> {
//TODO remove this
fn load_image_grids(user: &SteamUsersInfo) -> Vec<ShortcutOwned> {
let user_info = crate::steam::get_shortcuts_for_user(user);
match user_info {
Ok(user_info) => {
@@ -336,22 +330,6 @@ fn load_image_grids(
user_folder.pop();
let mut shortcuts = user_info.shortcuts;
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
}
Err(_err) => {
+1 -1
View File
@@ -81,7 +81,7 @@ impl MyEguiApp {
}
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.widgets.inactive.bg_fill = EXTRA_BACKGROUND_COLOR;
scroll_style.visuals.widgets.active.bg_fill = EXTRA_BACKGROUND_COLOR;
+1 -1
View File
@@ -42,7 +42,7 @@ impl MyEguiApp {
pub(crate) fn render_import_games(&mut self, ui: &mut egui::Ui) {
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.widgets.inactive.bg_fill = EXTRA_BACKGROUND_COLOR;
scroll_style.visuals.widgets.active.bg_fill = EXTRA_BACKGROUND_COLOR;
+1 -1
View File
@@ -13,7 +13,7 @@ impl MyEguiApp {
pub(crate) fn render_settings(&mut self, ui: &mut egui::Ui) {
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.widgets.inactive.bg_fill = EXTRA_BACKGROUND_COLOR;
scroll_style.visuals.widgets.active.bg_fill = EXTRA_BACKGROUND_COLOR;
+26 -58
View File
@@ -1,7 +1,9 @@
use std::{collections::HashMap, error::Error, time::Duration};
use eframe::{egui, App, Frame};
use egui::{ImageButton, Rounding, Stroke, TextureHandle};
use egui::{
ImageButton, Rounding, Stroke, Vec2
};
use tokio::{
runtime::Runtime,
sync::watch::{self, Receiver},
@@ -20,19 +22,14 @@ use super::{
BACKGROUND_COLOR, BG_STROKE_COLOR, EXTRA_BACKGROUND_COLOR, LIGHT_ORANGE, ORANGE, PURLPLE,
TEXT_COLOR,
},
ui_images::{get_import_image, get_logo, get_logo_icon, get_save_image},
ui_images::get_logo_icon,
ui_import_games::FetcStatus,
BackupState, DiconnectState,
};
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<(
String,
Receiver<FetcStatus<eyre::Result<Vec<ShortcutToImport>>>>,
@@ -59,7 +56,6 @@ pub struct MyEguiApp {
selected_menu: Menues,
pub(crate) settings: Settings,
pub(crate) rt: Runtime,
ui_images: UiImages,
pub(crate) games_to_sync: GamesToSync,
pub(crate) status_reciever: Receiver<SyncProgress>,
pub(crate) image_selected_state: ImageSelectState,
@@ -81,7 +77,6 @@ impl MyEguiApp {
settings,
rt: runtime,
games_to_sync,
ui_images: UiImages::default(),
status_reciever: watch::channel(SyncProgress::NotStarted).1,
image_selected_state: ImageSelectState::default(),
backup_state: BackupState::default(),
@@ -119,12 +114,12 @@ impl MyEguiApp {
}
}
let all_ready = all_ready(&self.games_to_sync);
let texture = self.get_import_image(ui);
let size = texture.size_vec2();
let image_button = ImageButton::new(texture, size * 0.40);
let import_image = egui::include_image!("../../resources/import_games_button.png");
let size = Vec2::new(200.,100.);
let image_button = ImageButton::new(import_image);
if all_ready && !syncing {
if ui
.add(image_button)
.add_sized(size,image_button)
.on_hover_text("Import your games into steam")
.clicked()
{
@@ -134,7 +129,7 @@ impl MyEguiApp {
self.run_sync_async();
}
} else {
ui.add(image_button)
ui.add_sized(size,image_button)
.on_hover_text("Waiting for sync to finish");
}
}
@@ -187,9 +182,8 @@ impl App for MyEguiApp {
.default_width(40.0)
.frame(frame)
.show(ctx, |ui| {
let texture = self.get_logo_image(ui);
let size = texture.size_vec2();
ui.image(texture, size);
let image = egui::include_image!("../../resources/logo32.png");
ui.image(image);
ui.add_space(SECTION_SPACING);
let menu_before = self.selected_menu.clone();
@@ -258,11 +252,14 @@ impl App for MyEguiApp {
egui::TopBottomPanel::new(egui::panel::TopBottomSide::Bottom, "Bottom Panel")
.frame(frame)
.show(ctx, |ui| {
let texture = self.get_save_image(ui);
let size = texture.size_vec2();
let save_button = ImageButton::new(texture, size * 0.5);
if ui.add(save_button).on_hover_text("Save settings").clicked() {
let image = egui::include_image!("../../resources/save.png");
let size = image.texture_size().unwrap_or_default();
let save_button = ImageButton::new(image);
if ui
.add_sized(size * 0.5, save_button)
.on_hover_text("Save settings")
.clicked()
{
if let Err(err) = save_settings(&self.settings, &self.platforms) {
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.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) {
#[cfg(target_family = "unix")]
ctx.set_pixels_per_point(0.999);
@@ -340,6 +307,7 @@ fn setup(ctx: &egui::Context) {
let mut style: egui::Style = (*ctx.style()).clone();
create_style(&mut style);
ctx.set_style(style);
egui_extras::install_image_loaders(ctx);
}
pub fn run_sync() -> eyre::Result<()> {
let mut app = MyEguiApp::new()?;
@@ -354,11 +322,10 @@ pub fn run_ui(args: Vec<String>) -> eyre::Result<()>{
let app = MyEguiApp::new()?;
let no_v_sync = args.contains(&"--no-vsync".to_string());
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 {
fullscreen,
maximized: true,
//initial_window_size: Some(egui::Vec2 { x: 1280., y: 800. }),
icon_data: Some(get_logo_icon()),
viewport,
vsync: !no_v_sync,
..Default::default()
};
@@ -368,7 +335,8 @@ pub fn run_ui(args: Vec<String>) -> eyre::Result<()>{
Box::new(|cc| {
setup(&cc.egui_ctx);
Box::new(app)
}));
}),
);
run_result.map_err(|e| eyre::eyre!("Could not initialize: {:?}", e))
}