This commit is contained in:
Philip Kristoffersen
2022-09-11 20:06:29 +02:00
9 changed files with 466 additions and 424 deletions
+1
View File
@@ -20,6 +20,7 @@ pub(crate) fn get_egs_manifests(
.filter_map(get_manifest_item); .filter_map(get_manifest_item);
let mut manifests = vec![]; let mut manifests = vec![];
for mut manifest in all_manifests { for mut manifest in all_manifests {
manifest.manifest_location = manifest.manifest_location;
#[cfg(target_family = "unix")] #[cfg(target_family = "unix")]
{ {
if let Some(compat_folder) = locations.compat_folder_path.as_ref() { if let Some(compat_folder) = locations.compat_folder_path.as_ref() {
+4 -4
View File
@@ -22,9 +22,9 @@ impl HeroicGameType {
HeroicGameType::Epic(g) => g.app_name.as_ref(), HeroicGameType::Epic(g) => g.app_name.as_ref(),
HeroicGameType::Gog(g, _) => g.game_id.as_ref(), HeroicGameType::Gog(g, _) => g.game_id.as_ref(),
HeroicGameType::Heroic { HeroicGameType::Heroic {
title, title:_,
app_name, app_name,
install_mode, install_mode:_,
} => app_name, } => app_name,
} }
} }
@@ -35,8 +35,8 @@ impl HeroicGameType {
HeroicGameType::Gog(g, _) => g.name.as_ref(), HeroicGameType::Gog(g, _) => g.name.as_ref(),
HeroicGameType::Heroic { HeroicGameType::Heroic {
title, title,
app_name, app_name:_,
install_mode, install_mode:_,
} => title.as_ref(), } => title.as_ref(),
} }
} }
+3 -2
View File
@@ -3,6 +3,7 @@ mod config;
mod egs; mod egs;
mod flatpak; mod flatpak;
mod gog; mod gog;
#[cfg(target_family = "unix")]
mod heroic; mod heroic;
mod itch; mod itch;
mod legendary; mod legendary;
@@ -17,13 +18,13 @@ mod sync;
mod ui; mod ui;
mod uplay; mod uplay;
fn main(){ fn main() {
ensure_config_folder(); ensure_config_folder();
migration::migrate_config(); migration::migrate_config();
let args: Vec<String> = std::env::args().collect(); let args: Vec<String> = std::env::args().collect();
if args.contains(&"--no-ui".to_string()) { if args.contains(&"--no-ui".to_string()) {
ui::run_sync(); ui::run_sync();
} else { } else {
ui::run_ui(args); ui::run_ui(args);
} }
+7 -3
View File
@@ -1,10 +1,13 @@
use crate::{ use crate::{
amazon::AmazonSettings, config::get_config_file, egs::EpicGamesLauncherSettings, amazon::AmazonSettings, config::get_config_file, egs::EpicGamesLauncherSettings,
flatpak::FlatpakSettings, gog::GogSettings, heroic::HeroicSettings, itch::ItchSettings, flatpak::FlatpakSettings, gog::GogSettings, itch::ItchSettings, legendary::LegendarySettings,
legendary::LegendarySettings, lutris::settings::LutrisSettings, origin::OriginSettings, lutris::settings::LutrisSettings, origin::OriginSettings, steam::SteamSettings,
steam::SteamSettings, steamgriddb::SteamGridDbSettings, uplay::UplaySettings, steamgriddb::SteamGridDbSettings, uplay::UplaySettings,
}; };
#[cfg(target_family = "unix")]
use crate::heroic::HeroicSettings;
use config::{Config, ConfigError, Environment, File}; use config::{Config, ConfigError, Environment, File};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::env; use std::env;
@@ -23,6 +26,7 @@ pub struct Settings {
pub gog: GogSettings, pub gog: GogSettings,
pub uplay: UplaySettings, pub uplay: UplaySettings,
pub lutris: LutrisSettings, pub lutris: LutrisSettings,
#[cfg(target_family = "unix")]
pub heroic: HeroicSettings, pub heroic: HeroicSettings,
pub amazon: AmazonSettings, pub amazon: AmazonSettings,
pub flatpak: FlatpakSettings, pub flatpak: FlatpakSettings,
+3 -1
View File
@@ -3,7 +3,6 @@ use tokio::sync::watch::Sender;
use crate::{ use crate::{
egs::EpicPlatform, egs::EpicPlatform,
flatpak::FlatpakPlatform,
legendary::LegendaryPlatform, legendary::LegendaryPlatform,
lutris::lutris_platform::LutrisPlatform, lutris::lutris_platform::LutrisPlatform,
platform::Platform, platform::Platform,
@@ -19,6 +18,9 @@ use crate::{
#[cfg(target_family = "unix")] #[cfg(target_family = "unix")]
use crate::heroic::HeroicPlatform; use crate::heroic::HeroicPlatform;
#[cfg(target_family = "unix")]
use crate::flatpak::FlatpakPlatform;
use std::error::Error; use std::error::Error;
use crate::{gog::GogPlatform, itch::ItchPlatform, origin::OriginPlatform}; use crate::{gog::GogPlatform, itch::ItchPlatform, origin::OriginPlatform};
+56 -33
View File
@@ -1,6 +1,6 @@
use std::{ use std::{
path::{Path, PathBuf}, path::{Path, PathBuf},
sync::Arc, thread::Thread, sync::Arc,
}; };
use crate::{ use crate::{
@@ -9,7 +9,6 @@ use crate::{
steam::{get_shortcuts_paths, SteamUsersInfo}, steam::{get_shortcuts_paths, SteamUsersInfo},
steamgriddb::{get_image_extension, get_query_type, CachedSearch, ImageType, ToDownload}, steamgriddb::{get_image_extension, get_query_type, CachedSearch, ImageType, ToDownload},
}; };
use config::File;
use dashmap::DashMap; use dashmap::DashMap;
use egui::{ImageButton, ScrollArea}; use egui::{ImageButton, ScrollArea};
use futures::executor::block_on; use futures::executor::block_on;
@@ -41,6 +40,7 @@ pub enum TextureState {
Downloading, Downloading,
Downloaded, Downloaded,
Loaded(egui::TextureHandle), Loaded(egui::TextureHandle),
Failed,
} }
#[derive(Debug)] #[derive(Debug)]
@@ -149,7 +149,7 @@ impl MyEguiApp {
ui.heading(shortcut.name()); ui.heading(shortcut.name());
if let Some(possible_names) = state.possible_names.as_ref() { if let Some(possible_names) = state.possible_names.as_ref() {
if let Some(value) = render_possible_names(possible_names, ui,state) { if let Some(value) = render_possible_names(possible_names, ui, state) {
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() {
@@ -265,19 +265,22 @@ impl MyEguiApp {
TextureState::Downloaded => { TextureState::Downloaded => {
//Need to load //Need to load
let image_data = load_image_from_path(&image.thumbnail_path); let image_data = load_image_from_path(&image.thumbnail_path);
if let Ok(image_data) = image_data { match image_data {
let handle = ui.ctx().load_texture( Ok(image_data) => {
&image_key, let handle = ui.ctx().load_texture(
image_data, &image_key,
egui::TextureFilter::Linear, image_data,
); egui::TextureFilter::Linear,
*state.value_mut() = TextureState::Loaded(handle); );
*state.value_mut() = TextureState::Loaded(handle);
ui.horizontal(|ui| {
ui.spinner();
ui.label("Loading");
});
}
Err(_) => *state.value_mut() = TextureState::Failed,
} }
ui.ctx().request_repaint(); ui.ctx().request_repaint();
ui.horizontal(|ui| {
ui.spinner();
ui.label("Loading");
});
} }
TextureState::Loaded(texture_handle) => { TextureState::Loaded(texture_handle) => {
//need to show //need to show
@@ -288,6 +291,9 @@ impl MyEguiApp {
return Some(UserAction::ImageSelected(image.clone())); return Some(UserAction::ImageSelected(image.clone()));
} }
} }
TextureState::Failed => {
ui.label("Failed to load image");
}
} }
} }
None => { None => {
@@ -401,12 +407,12 @@ impl MyEguiApp {
.set_image_banned(&image_type, app_id, should_ban); .set_image_banned(&image_type, app_id, should_ban);
self.handle_image_type_clear(image_type); self.handle_image_type_clear(image_type);
} }
UserAction::ClearImages =>{ UserAction::ClearImages => {
for image_type in ImageType::all(){ for image_type in ImageType::all() {
self.handle_image_type_clear(*image_type); self.handle_image_type_clear(*image_type);
} }
self.handle_back_button_action(); self.handle_back_button_action();
}, }
}; };
} }
@@ -523,14 +529,15 @@ impl MyEguiApp {
let mut result = vec![]; let mut result = vec![];
for possible_image in &possible_images { for possible_image in &possible_images {
let ext = get_image_extension(&possible_image.mime); let ext = get_image_extension(&possible_image.mime);
let path = thumbnails_folder.join(format!("{}.{}",possible_image.id,ext)); let path =
thumbnails_folder.join(format!("{}.{}", possible_image.id, ext));
result.push(PossibleImage { result.push(PossibleImage {
thumbnail_path: path, thumbnail_path: path,
mime: possible_image.mime.clone(), mime: possible_image.mime.clone(),
thumbnail_url: possible_image.thumb.clone(), thumbnail_url: possible_image.thumb.clone(),
full_url: possible_image.url.clone(), full_url: possible_image.url.clone(),
id: possible_image.id, id: possible_image.id,
}); });
} }
let _ = tx.send(FetcStatus::Fetched(result)); let _ = tx.send(FetcStatus::Fetched(result));
} }
@@ -563,20 +570,25 @@ impl MyEguiApp {
let data_folder = Path::new(&user.steam_user_data_folder); let data_folder = Path::new(&user.steam_user_data_folder);
//Keep deleting images of this type untill we don't find any more //Keep deleting images of this type untill we don't find any more
let mut path = self.get_shortcut_image_path(data_folder); let mut path = self.get_shortcut_image_path(data_folder);
while Path::new(&path).exists(){ while Path::new(&path).exists() {
let _= std::fs::remove_file(&path); let _ = std::fs::remove_file(&path);
path = self.get_shortcut_image_path(data_folder); path = self.get_shortcut_image_path(data_folder);
} }
//Put the loaded thumbnail into the image handler map, we can use that for preview //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 full_image_key = to_download_to_path.to_string_lossy().to_string();
let _ = self.image_selected_state.image_handles.remove(&full_image_key); let _ = self
.image_selected_state
.image_handles
.remove(&full_image_key);
let thumbnail_key = image.thumbnail_path.to_string_lossy().to_string(); let thumbnail_key = image.thumbnail_path.to_string_lossy().to_string();
let thumbnail = self.image_selected_state.image_handles.remove(&thumbnail_key); let thumbnail = self
if let Some((key,thumbnail)) = thumbnail { .image_selected_state
.image_handles
.remove(&thumbnail_key);
if let Some((_key, thumbnail)) = thumbnail {
self.image_selected_state self.image_selected_state
.image_handles .image_handles
.insert(full_image_key, thumbnail); .insert(full_image_key, thumbnail);
@@ -601,7 +613,15 @@ impl MyEguiApp {
} }
fn get_shortcut_image_path(&self, data_folder: &Path) -> String { fn get_shortcut_image_path(&self, data_folder: &Path) -> String {
self.image_selected_state.selected_shortcut.as_ref().unwrap().key(&self.image_selected_state.image_type_selected.unwrap(), data_folder).1 self.image_selected_state
.selected_shortcut
.as_ref()
.unwrap()
.key(
&self.image_selected_state.image_type_selected.unwrap(),
data_folder,
)
.1
} }
fn clear_loaded_images(&mut self) { fn clear_loaded_images(&mut self) {
@@ -662,17 +682,17 @@ impl MyEguiApp {
fn render_possible_names( fn render_possible_names(
possible_names: &Vec<steamgriddb_api::search::SearchResult>, possible_names: &Vec<steamgriddb_api::search::SearchResult>,
ui: &mut egui::Ui, ui: &mut egui::Ui,
state: &ImageSelectState state: &ImageSelectState,
) -> Option<UserAction> { ) -> Option<UserAction> {
let mut grid_id_text = state.grid_id.map(|id| id.to_string()).unwrap_or_default(); let mut grid_id_text = state.grid_id.map(|id| id.to_string()).unwrap_or_default();
ui.label("SteamGridDB ID").on_hover_text("You can change this id to one you have found at the steamgriddb webpage"); ui.label("SteamGridDB ID")
if ui.text_edit_singleline(&mut grid_id_text) .on_hover_text("You can change this id to one you have found at the steamgriddb webpage");
.changed() { if ui.text_edit_singleline(&mut grid_id_text).changed() {
if let Ok(grid_id) = grid_id_text.parse::<usize>() { if let Ok(grid_id) = grid_id_text.parse::<usize>() {
return Some(UserAction::GridIdChanged(grid_id)); return Some(UserAction::GridIdChanged(grid_id));
} }
}; };
for possible in possible_names { for possible in possible_names {
if ui.button(&possible.name).clicked() { if ui.button(&possible.name).clicked() {
return Some(UserAction::GridIdChanged(possible.id)); return Some(UserAction::GridIdChanged(possible.id));
@@ -680,7 +700,11 @@ fn render_possible_names(
} }
ui.separator(); ui.separator();
if ui.button("Clear all images").on_hover_text("Clicking this deletes all images for this shortcut").clicked(){ if ui
.button("Clear all images")
.on_hover_text("Clicking this deletes all images for this shortcut")
.clicked()
{
return Some(UserAction::ClearImages); return Some(UserAction::ClearImages);
} }
None None
@@ -700,7 +724,6 @@ fn render_steam_game_select(ui: &mut egui::Ui, state: &ImageSelectState) -> Opti
} }
fn render_shortcut_images(ui: &mut egui::Ui, state: &ImageSelectState) -> Option<UserAction> { fn render_shortcut_images(ui: &mut egui::Ui, state: &ImageSelectState) -> Option<UserAction> {
if ui if ui
.button("Click here if the images are for a wrong game") .button("Click here if the images are for a wrong game")
.clicked() .clicked()
+374 -369
View File
@@ -1,369 +1,374 @@
use copypasta::ClipboardProvider; use copypasta::ClipboardProvider;
use eframe::egui; use eframe::egui;
use egui::ScrollArea; use egui::ScrollArea;
use crate::{egs::EpicPlatform, heroic::HeroicPlatform}; use crate::{egs::EpicPlatform};
#[cfg(target_family = "unix")]
use super::{ use crate::heroic::HeroicPlatform;
ui_colors::{BACKGROUND_COLOR, EXTRA_BACKGROUND_COLOR},
MyEguiApp, use super::{
}; ui_colors::{BACKGROUND_COLOR, EXTRA_BACKGROUND_COLOR},
pub const SECTION_SPACING: f32 = 25.0; MyEguiApp,
const VERSION: &str = env!("CARGO_PKG_VERSION"); };
pub const SECTION_SPACING: f32 = 25.0;
impl MyEguiApp { const VERSION: &str = env!("CARGO_PKG_VERSION");
pub(crate) fn render_settings(&mut self, ui: &mut egui::Ui) {
ui.heading("Settings"); impl MyEguiApp {
pub(crate) fn render_settings(&mut self, ui: &mut egui::Ui) {
let mut scroll_style = ui.style_mut(); ui.heading("Settings");
scroll_style.visuals.extreme_bg_color = BACKGROUND_COLOR;
scroll_style.visuals.widgets.inactive.bg_fill = EXTRA_BACKGROUND_COLOR; let mut scroll_style = ui.style_mut();
scroll_style.visuals.widgets.active.bg_fill = EXTRA_BACKGROUND_COLOR; scroll_style.visuals.extreme_bg_color = BACKGROUND_COLOR;
scroll_style.visuals.selection.bg_fill = EXTRA_BACKGROUND_COLOR; scroll_style.visuals.widgets.inactive.bg_fill = EXTRA_BACKGROUND_COLOR;
scroll_style.visuals.widgets.hovered.bg_fill = EXTRA_BACKGROUND_COLOR; scroll_style.visuals.widgets.active.bg_fill = EXTRA_BACKGROUND_COLOR;
scroll_style.visuals.selection.bg_fill = EXTRA_BACKGROUND_COLOR;
ScrollArea::vertical() scroll_style.visuals.widgets.hovered.bg_fill = EXTRA_BACKGROUND_COLOR;
.stick_to_right(true)
.auto_shrink([false, true]) ScrollArea::vertical()
.show(ui, |ui| { .stick_to_right(true)
ui.reset_style(); .auto_shrink([false, true])
.show(ui, |ui| {
self.render_steamgriddb_settings(ui); ui.reset_style();
self.render_steam_settings(ui); self.render_steamgriddb_settings(ui);
self.render_epic_settings(ui); self.render_steam_settings(ui);
#[cfg(target_family = "unix")] self.render_epic_settings(ui);
{
self.render_heroic_settings(ui); #[cfg(target_family = "unix")]
} {
self.render_heroic_settings(ui);
self.render_legendary_settings(ui); }
self.render_itch_settings(ui);
self.render_origin_settings(ui); self.render_legendary_settings(ui);
self.render_gog_settings(ui); self.render_itch_settings(ui);
self.render_uplay_settings(ui); self.render_origin_settings(ui);
self.render_lutris_settings(ui); self.render_gog_settings(ui);
#[cfg(windows)] self.render_uplay_settings(ui);
{ self.render_lutris_settings(ui);
self.render_amazon_settings(ui); #[cfg(windows)]
} {
self.render_amazon_settings(ui);
}
#[cfg(target_family = "unix")]
{
self.render_flatpak_settings(ui); #[cfg(target_family = "unix")]
} {
self.render_flatpak_settings(ui);
}
ui.add_space(SECTION_SPACING);
ui.label(format!("Version: {}", VERSION));
}); ui.add_space(SECTION_SPACING);
} ui.label(format!("Version: {}", VERSION));
});
fn render_flatpak_settings(&mut self, ui: &mut egui::Ui) { }
ui.heading("Flatpak");
ui.checkbox(&mut self.settings.flatpak.enabled, "Import from Flatpak"); #[cfg(target_family = "unix")]
fn render_flatpak_settings(&mut self, ui: &mut egui::Ui) {
ui.add_space(SECTION_SPACING); ui.heading("Flatpak");
} ui.checkbox(&mut self.settings.flatpak.enabled, "Import from Flatpak");
ui.add_space(SECTION_SPACING);
fn render_heroic_settings(&mut self, ui: &mut egui::Ui) { }
ui.heading("Heroic");
ui.checkbox(&mut self.settings.heroic.enabled, "Import from Heroic"); #[cfg(target_family = "unix")]
ui.checkbox(&mut self.settings.heroic.default_launch_through_heroic, "Always launch games through Heroic"); fn render_heroic_settings(&mut self, ui: &mut egui::Ui) {
let safe_mode_header = match (self.settings.heroic.default_launch_through_heroic,self.settings.heroic.launch_games_through_heroic.len()) { ui.heading("Heroic");
(false,0) => "Force games to launch through Heroic Launcher".to_string(), ui.checkbox(&mut self.settings.heroic.enabled, "Import from Heroic");
(false,1) => "One game forced to launch through Heroic Launcher".to_string(), ui.checkbox(&mut self.settings.heroic.default_launch_through_heroic, "Always launch games through Heroic");
(false,x) => format!("{} games forced to launch through Heroic Launcher", x), let safe_mode_header = match (self.settings.heroic.default_launch_through_heroic,self.settings.heroic.launch_games_through_heroic.len()) {
(false,0) => "Force games to launch through Heroic Launcher".to_string(),
(true,0) => "Force games to launch directly".to_string(), (false,1) => "One game forced to launch through Heroic Launcher".to_string(),
(true,1) => "One game forced to launch directly".to_string(), (false,x) => format!("{} games forced to launch through Heroic Launcher", x),
(true,x) => format!("{} games forced to launch directly", x),
(true,0) => "Force games to launch directly".to_string(),
}; (true,1) => "One game forced to launch directly".to_string(),
egui::CollapsingHeader::new(safe_mode_header) (true,x) => format!("{} games forced to launch directly", x),
.id_source("Heroic_Launcher_safe_launch")
.show(ui, |ui| { };
if egui::CollapsingHeader::new(safe_mode_header)
self.settings.heroic.default_launch_through_heroic{ .id_source("Heroic_Launcher_safe_launch")
ui.label("Some games work best when launched directly, select those games below and BoilR will create shortcuts that launch the games directly."); .show(ui, |ui| {
if
} else{ self.settings.heroic.default_launch_through_heroic{
ui.label("Some games must be started from the Heroic Launcher, select those games below and BoilR will create shortcuts that opens the games through the Heroic Launcher."); ui.label("Some games work best when launched directly, select those games below and BoilR will create shortcuts that launch the games directly.");
} } else{
let manifests =self.heroic_games.get_or_insert_with(||{ ui.label("Some games must be started from the Heroic Launcher, select those games below and BoilR will create shortcuts that opens the games through the Heroic Launcher.");
let heroic_setting = self.settings.heroic.clone();
}
let heroic_platform =HeroicPlatform{ #[cfg(target_family = "unix")]{
settings:heroic_setting let manifests =self.heroic_games.get_or_insert_with(||{
}; let heroic_setting = self.settings.heroic.clone();
heroic_platform.get_heroic_games()
}); let heroic_platform =HeroicPlatform{
settings:heroic_setting
let safe_open_games = &mut self.settings.heroic.launch_games_through_heroic; };
for manifest in manifests{ heroic_platform.get_heroic_games()
let key = manifest.app_name(); });
let display_name = manifest.title();
let mut safe_open = safe_open_games.contains(&display_name.to_string()) || safe_open_games.contains(&key.to_string()); let safe_open_games = &mut self.settings.heroic.launch_games_through_heroic;
if ui.checkbox(&mut safe_open, display_name).clicked(){ for manifest in manifests{
if safe_open{ let key = manifest.app_name();
safe_open_games.push(key.to_string()); let display_name = manifest.title();
}else{ let mut safe_open = safe_open_games.contains(&display_name.to_string()) || safe_open_games.contains(&key.to_string());
safe_open_games.retain(|m| m!= display_name && m!= key); if ui.checkbox(&mut safe_open, display_name).clicked(){
} if safe_open{
} safe_open_games.push(key.to_string());
} }else{
}) ; safe_open_games.retain(|m| m!= display_name && m!= key);
ui.add_space(SECTION_SPACING); }
} }
}
fn render_lutris_settings(&mut self, ui: &mut egui::Ui) { }
ui.heading("Lutris"); }) ;
ui.checkbox(&mut self.settings.lutris.enabled, "Import from Lutris"); ui.add_space(SECTION_SPACING);
if self.settings.lutris.enabled { }
ui.checkbox(&mut self.settings.lutris.flatpak, "Flatpak version");
if !self.settings.lutris.flatpak { fn render_lutris_settings(&mut self, ui: &mut egui::Ui) {
ui.horizontal(|ui| { ui.heading("Lutris");
let lutris_location = &mut self.settings.lutris.executable; ui.checkbox(&mut self.settings.lutris.enabled, "Import from Lutris");
ui.label("Lutris Location: "); if self.settings.lutris.enabled {
ui.text_edit_singleline(lutris_location); ui.checkbox(&mut self.settings.lutris.flatpak, "Flatpak version");
}); if !self.settings.lutris.flatpak {
} else { ui.horizontal(|ui| {
ui.horizontal(|ui| { let lutris_location = &mut self.settings.lutris.executable;
let flatpak_image = &mut self.settings.lutris.flatpak_image; ui.label("Lutris Location: ");
ui.label("Flatpak image"); ui.text_edit_singleline(lutris_location);
ui.text_edit_singleline(flatpak_image); });
}); } else {
} ui.horizontal(|ui| {
} let flatpak_image = &mut self.settings.lutris.flatpak_image;
ui.add_space(SECTION_SPACING); ui.label("Flatpak image");
} ui.text_edit_singleline(flatpak_image);
});
#[cfg(windows)] }
fn render_amazon_settings(&mut self, ui: &mut egui::Ui) { }
ui.heading("Amazon"); ui.add_space(SECTION_SPACING);
ui.checkbox(&mut self.settings.amazon.enabled, "Import from Amazon"); }
ui.add_space(SECTION_SPACING);
} #[cfg(windows)]
fn render_amazon_settings(&mut self, ui: &mut egui::Ui) {
fn render_uplay_settings(&mut self, ui: &mut egui::Ui) { ui.heading("Amazon");
ui.heading("Uplay"); ui.checkbox(&mut self.settings.amazon.enabled, "Import from Amazon");
ui.checkbox(&mut self.settings.uplay.enabled, "Import from Uplay"); ui.add_space(SECTION_SPACING);
ui.add_space(SECTION_SPACING); }
}
fn render_uplay_settings(&mut self, ui: &mut egui::Ui) {
fn render_gog_settings(&mut self, ui: &mut egui::Ui) { ui.heading("Uplay");
ui.heading("GoG Galaxy"); ui.checkbox(&mut self.settings.uplay.enabled, "Import from Uplay");
ui.checkbox(&mut self.settings.gog.enabled, "Import from GoG Galaxy"); ui.add_space(SECTION_SPACING);
if self.settings.gog.enabled { }
ui.horizontal(|ui| {
let mut empty_string = "".to_string(); fn render_gog_settings(&mut self, ui: &mut egui::Ui) {
let itch_location = self ui.heading("GoG Galaxy");
.settings ui.checkbox(&mut self.settings.gog.enabled, "Import from GoG Galaxy");
.gog if self.settings.gog.enabled {
.location ui.horizontal(|ui| {
.as_mut() let mut empty_string = "".to_string();
.unwrap_or(&mut empty_string); let itch_location = self
ui.label("GoG Galaxy Folder: "); .settings
if ui.text_edit_singleline(itch_location).changed() { .gog
self.settings.gog.location = Some(itch_location.to_string()); .location
} .as_mut()
}); .unwrap_or(&mut empty_string);
} ui.label("GoG Galaxy Folder: ");
ui.add_space(SECTION_SPACING); if ui.text_edit_singleline(itch_location).changed() {
} self.settings.gog.location = Some(itch_location.to_string());
}
fn render_origin_settings(&mut self, ui: &mut egui::Ui) { });
ui.heading("Origin"); }
ui.checkbox(&mut self.settings.origin.enabled, "Import from Origin"); ui.add_space(SECTION_SPACING);
ui.add_space(SECTION_SPACING); }
}
fn render_origin_settings(&mut self, ui: &mut egui::Ui) {
fn render_itch_settings(&mut self, ui: &mut egui::Ui) { ui.heading("Origin");
ui.heading("Itch.io"); ui.checkbox(&mut self.settings.origin.enabled, "Import from Origin");
ui.checkbox(&mut self.settings.itch.enabled, "Import from Itch.io"); ui.add_space(SECTION_SPACING);
if self.settings.itch.enabled { }
ui.horizontal(|ui| {
let mut empty_string = "".to_string(); fn render_itch_settings(&mut self, ui: &mut egui::Ui) {
let itch_location = self ui.heading("Itch.io");
.settings ui.checkbox(&mut self.settings.itch.enabled, "Import from Itch.io");
.itch if self.settings.itch.enabled {
.location ui.horizontal(|ui| {
.as_mut() let mut empty_string = "".to_string();
.unwrap_or(&mut empty_string); let itch_location = self
ui.label("Itch.io Folder: "); .settings
if ui.text_edit_singleline(itch_location).changed() { .itch
self.settings.itch.location = if itch_location.is_empty(){ .location
None .as_mut()
}else { .unwrap_or(&mut empty_string);
Some(itch_location.to_string()) ui.label("Itch.io Folder: ");
}; if ui.text_edit_singleline(itch_location).changed() {
}else{ self.settings.itch.location = if itch_location.is_empty(){
if !itch_location.is_empty(){ None
if ui.button("Reset").on_hover_text("Reset the itch path, let BoilR guess again").clicked(){ }else {
self.settings.itch.location = None; Some(itch_location.to_string())
} };
} }else{
} if !itch_location.is_empty(){
if ui.button("Reset").on_hover_text("Reset the itch path, let BoilR guess again").clicked(){
}); self.settings.itch.location = None;
#[cfg(target_family = "unix")] }
{ }
ui.checkbox(&mut self.settings.itch.create_symlinks, "Create symlinks"); }
}
} });
ui.add_space(SECTION_SPACING); #[cfg(target_family = "unix")]
} {
ui.checkbox(&mut self.settings.itch.create_symlinks, "Create symlinks");
fn render_steam_settings(&mut self, ui: &mut egui::Ui) { }
ui.heading("Steam"); }
ui.horizontal(|ui| { ui.add_space(SECTION_SPACING);
let mut empty_string = "".to_string(); }
let steam_location = self
.settings fn render_steam_settings(&mut self, ui: &mut egui::Ui) {
.steam ui.heading("Steam");
.location ui.horizontal(|ui| {
.as_mut() let mut empty_string = "".to_string();
.unwrap_or(&mut empty_string); let steam_location = self
ui.label("Steam Location: "); .settings
if ui.text_edit_singleline(steam_location).changed() { .steam
if steam_location.trim().is_empty(){ .location
self.settings.steam.location = None; .as_mut()
}else{ .unwrap_or(&mut empty_string);
self.settings.steam.location = Some(steam_location.to_string()); ui.label("Steam Location: ");
} if ui.text_edit_singleline(steam_location).changed() {
if steam_location.trim().is_empty(){
} self.settings.steam.location = None;
}); }else{
ui.checkbox( self.settings.steam.location = Some(steam_location.to_string());
&mut self.settings.steam.create_collections, }
"Create collections",
) }
.on_hover_text("Tries to create a games collection for each platform"); });
ui.checkbox(&mut self.settings.steam.optimize_for_big_picture, "Optimize for big picture").on_hover_text("Set icons to be larger horizontal images, this looks nice in steam big picture mode, but a bit off in desktop mode"); ui.checkbox(
ui.checkbox( &mut self.settings.steam.create_collections,
&mut self.settings.steam.stop_steam, "Create collections",
"Stop Steam before import", )
) .on_hover_text("Tries to create a games collection for each platform");
.on_hover_text("Stops Steam if it is running when import starts"); ui.checkbox(&mut self.settings.steam.optimize_for_big_picture, "Optimize for big picture").on_hover_text("Set icons to be larger horizontal images, this looks nice in steam big picture mode, but a bit off in desktop mode");
ui.checkbox( ui.checkbox(
&mut self.settings.steam.start_steam, &mut self.settings.steam.stop_steam,
"Start Steam after import", "Stop Steam before import",
) )
.on_hover_text("Starts Steam is it is not running after the import"); .on_hover_text("Stops Steam if it is running when import starts");
ui.add_space(SECTION_SPACING); ui.checkbox(
} &mut self.settings.steam.start_steam,
"Start Steam after import",
fn render_steamgriddb_settings(&mut self, ui: &mut egui::Ui) { )
ui.heading("SteamGridDB"); .on_hover_text("Starts Steam is it is not running after the import");
ui.checkbox(&mut self.settings.steamgrid_db.enabled, "Download images"); ui.add_space(SECTION_SPACING);
if self.settings.steamgrid_db.enabled { }
ui.horizontal(|ui| {
let mut auth_key = self fn render_steamgriddb_settings(&mut self, ui: &mut egui::Ui) {
.settings ui.heading("SteamGridDB");
.steamgrid_db ui.checkbox(&mut self.settings.steamgrid_db.enabled, "Download images");
.auth_key if self.settings.steamgrid_db.enabled {
.clone() ui.horizontal(|ui| {
.unwrap_or_default(); let mut auth_key = self
ui.label("Authentication key: "); .settings
if ui.text_edit_singleline(&mut auth_key).changed() { .steamgrid_db
if auth_key.is_empty() { .auth_key
self.settings.steamgrid_db.auth_key = None; .clone()
} else { .unwrap_or_default();
self.settings.steamgrid_db.auth_key = Some(auth_key.to_string()); ui.label("Authentication key: ");
} if ui.text_edit_singleline(&mut auth_key).changed() {
} if auth_key.is_empty() {
if auth_key.is_empty() && ui.button("Paste from clipboard").clicked(){ self.settings.steamgrid_db.auth_key = None;
if let Ok(mut clipboard_ctx) = copypasta::ClipboardContext::new() { } else {
if let Ok(content) = clipboard_ctx.get_contents() { self.settings.steamgrid_db.auth_key = Some(auth_key.to_string());
self.settings.steamgrid_db.auth_key = Some(content); }
} }
} if auth_key.is_empty() && ui.button("Paste from clipboard").clicked(){
} if let Ok(mut clipboard_ctx) = copypasta::ClipboardContext::new() {
}); if let Ok(content) = clipboard_ctx.get_contents() {
ui.horizontal(|ui| { self.settings.steamgrid_db.auth_key = Some(content);
ui.label( }
"To download images you need an API Key from SteamGridDB, you can find yours", }
); }
ui.hyperlink_to( });
"here", ui.horizontal(|ui| {
"https://www.steamgriddb.com/profile/preferences/api", ui.label(
) "To download images you need an API Key from SteamGridDB, you can find yours",
}); );
ui.checkbox(&mut self.settings.steamgrid_db.prefer_animated, "Prefer animated images").on_hover_text("Prefer downloading animated images over static images (this can slow Steam down but looks neat)"); ui.hyperlink_to(
ui.checkbox( "here",
&mut self.settings.steamgrid_db.only_download_boilr_images, "https://www.steamgriddb.com/profile/preferences/api",
"Only download images for BoilR shortcuts", )
); });
} ui.checkbox(&mut self.settings.steamgrid_db.prefer_animated, "Prefer animated images").on_hover_text("Prefer downloading animated images over static images (this can slow Steam down but looks neat)");
ui.add_space(SECTION_SPACING); ui.checkbox(
} &mut self.settings.steamgrid_db.only_download_boilr_images,
"Only download images for BoilR shortcuts",
fn render_legendary_settings(&mut self, ui: &mut egui::Ui) { );
ui.heading("Legendary & Rare"); }
ui.checkbox( ui.add_space(SECTION_SPACING);
&mut self.settings.legendary.enabled, }
"Import from Legendary & Rare",
); fn render_legendary_settings(&mut self, ui: &mut egui::Ui) {
if self.settings.legendary.enabled { ui.heading("Legendary & Rare");
ui.horizontal(|ui| { ui.checkbox(
let mut empty_string = "".to_string(); &mut self.settings.legendary.enabled,
let legendary_location = self "Import from Legendary & Rare",
.settings );
.legendary if self.settings.legendary.enabled {
.executable ui.horizontal(|ui| {
.as_mut() let mut empty_string = "".to_string();
.unwrap_or(&mut empty_string); let legendary_location = self
ui.label("Legendary Executable: ") .settings
.on_hover_text("The location of the legendary executable to use"); .legendary
if ui.text_edit_singleline(legendary_location).changed() { .executable
self.settings.legendary.executable = Some(legendary_location.to_string()); .as_mut()
} .unwrap_or(&mut empty_string);
}); ui.label("Legendary Executable: ")
} .on_hover_text("The location of the legendary executable to use");
ui.add_space(SECTION_SPACING); if ui.text_edit_singleline(legendary_location).changed() {
} self.settings.legendary.executable = Some(legendary_location.to_string());
}
fn render_epic_settings(&mut self, ui: &mut egui::Ui) { });
let epic_settings = &mut self.settings.epic_games; }
ui.heading("Epic Games"); ui.add_space(SECTION_SPACING);
ui.checkbox(&mut epic_settings.enabled, "Import from Epic Games"); }
if epic_settings.enabled {
let safe_mode_header = match epic_settings.safe_launch.len() { fn render_epic_settings(&mut self, ui: &mut egui::Ui) {
0 => "Force games to launch through Epic Launcher".to_string(), let epic_settings = &mut self.settings.epic_games;
1 => "One game forced to launch through Epic Launcher".to_string(), ui.heading("Epic Games");
x => format!("{} games forced to launch through Epic Launcher", x), ui.checkbox(&mut epic_settings.enabled, "Import from Epic Games");
}; if epic_settings.enabled {
let safe_mode_header = match epic_settings.safe_launch.len() {
egui::CollapsingHeader::new(safe_mode_header) 0 => "Force games to launch through Epic Launcher".to_string(),
.id_source("Epic_Launcher_safe_launch") 1 => "One game forced to launch through Epic Launcher".to_string(),
.show(ui, |ui| { x => format!("{} games forced to launch through Epic Launcher", x),
ui.label("Some games must be started from the Epic Launcher, select those games below and BoilR will create shortcuts that opens the games through the Epic Launcher."); };
let manifests =self.epic_manifests.get_or_insert_with(||{
let epic_platform = EpicPlatform::new(epic_settings); egui::CollapsingHeader::new(safe_mode_header)
let manifests = crate::platform::Platform::get_shortcuts(&epic_platform); .id_source("Epic_Launcher_safe_launch")
manifests.unwrap_or_default() .show(ui, |ui| {
}); ui.label("Some games must be started from the Epic Launcher, select those games below and BoilR will create shortcuts that opens the games through the Epic Launcher.");
let mut safe_open_games = epic_settings.safe_launch.clone(); let manifests =self.epic_manifests.get_or_insert_with(||{
for manifest in manifests{ let epic_platform = EpicPlatform::new(epic_settings);
let key = manifest.get_key(); let manifests = crate::platform::Platform::get_shortcuts(&epic_platform);
let display_name = &manifest.display_name; manifests.unwrap_or_default()
let mut safe_open = safe_open_games.contains(display_name) || safe_open_games.contains(&key); });
if ui.checkbox(&mut safe_open, display_name).clicked(){ let mut safe_open_games = epic_settings.safe_launch.clone();
if safe_open{ for manifest in manifests{
safe_open_games.push(key); let key = manifest.get_key();
}else{ let display_name = &manifest.display_name;
safe_open_games.retain(|m| m!= display_name && m!= &key); let mut safe_open = safe_open_games.contains(display_name) || safe_open_games.contains(&key);
} if ui.checkbox(&mut safe_open, display_name).clicked(){
} if safe_open{
} safe_open_games.push(key);
epic_settings.safe_launch = safe_open_games; }else{
}) ; safe_open_games.retain(|m| m!= display_name && m!= &key);
ui.add_space(SECTION_SPACING); }
} }
} }
} epic_settings.safe_launch = safe_open_games;
}) ;
ui.add_space(SECTION_SPACING);
}
}
}
+16 -12
View File
@@ -1,19 +1,15 @@
use std::{env::Args, error::Error}; #[cfg(target_family = "unix")]
use crate::heroic::HeroicGameType;
use eframe::{egui, App, Frame}; use eframe::{egui, App, Frame};
use egui::{Button, ImageButton, Rounding, Stroke, TextureHandle}; use egui::{ImageButton, Rounding, Stroke, TextureHandle};
use steam_shortcuts_util::shortcut::ShortcutOwned; use steam_shortcuts_util::shortcut::ShortcutOwned;
use tokio::{ use tokio::{
runtime::Runtime, runtime::Runtime,
sync::watch::{self, Receiver}, sync::watch::{self, Receiver},
}; };
use crate::{ use crate::{egs::ManifestItem, settings::Settings, sync::SyncProgress};
egs::ManifestItem,
heroic::{HeroicGame, HeroicGameType},
settings::Settings,
sync::SyncProgress,
};
use super::{ use super::{
ui_colors::{ ui_colors::{
@@ -42,6 +38,7 @@ pub struct MyEguiApp {
pub(crate) games_to_sync: Receiver<FetcStatus<Vec<(String, Vec<ShortcutOwned>)>>>, pub(crate) games_to_sync: Receiver<FetcStatus<Vec<(String, Vec<ShortcutOwned>)>>>,
pub(crate) status_reciever: Receiver<SyncProgress>, pub(crate) status_reciever: Receiver<SyncProgress>,
pub(crate) epic_manifests: Option<Vec<ManifestItem>>, pub(crate) epic_manifests: Option<Vec<ManifestItem>>,
#[cfg(target_family = "unix")]
pub(crate) heroic_games: Option<Vec<HeroicGameType>>, pub(crate) heroic_games: Option<Vec<HeroicGameType>>,
pub(crate) image_selected_state: ImageSelectState, pub(crate) image_selected_state: ImageSelectState,
pub(crate) backup_state: BackupState, pub(crate) backup_state: BackupState,
@@ -59,6 +56,7 @@ impl MyEguiApp {
ui_images: UiImages::default(), ui_images: UiImages::default(),
status_reciever: watch::channel(SyncProgress::NotStarted).1, status_reciever: watch::channel(SyncProgress::NotStarted).1,
epic_manifests: None, epic_manifests: None,
#[cfg(target_family = "unix")]
heroic_games: None, heroic_games: None,
image_selected_state: ImageSelectState::default(), image_selected_state: ImageSelectState::default(),
backup_state: BackupState::default(), backup_state: BackupState::default(),
@@ -243,21 +241,27 @@ impl MyEguiApp {
fn get_import_image(&mut self, ui: &mut egui::Ui) -> &mut TextureHandle { fn get_import_image(&mut self, ui: &mut egui::Ui) -> &mut TextureHandle {
self.ui_images.import_button.get_or_insert_with(|| { self.ui_images.import_button.get_or_insert_with(|| {
// Load the texture only once. // Load the texture only once.
ui.ctx().load_texture("import_image", get_import_image(),egui::TextureFilter::Linear) ui.ctx().load_texture(
"import_image",
get_import_image(),
egui::TextureFilter::Linear,
)
}) })
} }
fn get_save_image(&mut self, ui: &mut egui::Ui) -> &mut TextureHandle { fn get_save_image(&mut self, ui: &mut egui::Ui) -> &mut TextureHandle {
self.ui_images.save_button.get_or_insert_with(|| { self.ui_images.save_button.get_or_insert_with(|| {
// Load the texture only once. // Load the texture only once.
ui.ctx().load_texture("save_image", get_save_image(),egui::TextureFilter::Linear) ui.ctx()
.load_texture("save_image", get_save_image(), egui::TextureFilter::Linear)
}) })
} }
fn get_logo_image(&mut self, ui: &mut egui::Ui) -> &mut TextureHandle { fn get_logo_image(&mut self, ui: &mut egui::Ui) -> &mut TextureHandle {
self.ui_images.logo_32.get_or_insert_with(|| { self.ui_images.logo_32.get_or_insert_with(|| {
// Load the texture only once. // Load the texture only once.
ui.ctx().load_texture("logo32", get_logo(),egui::TextureFilter::Linear) ui.ctx()
.load_texture("logo32", get_logo(), egui::TextureFilter::Linear)
}) })
} }
} }
@@ -275,7 +279,7 @@ pub fn run_sync() {
app.run_sync(true); app.run_sync(true);
} }
pub fn run_ui(args: Vec<String>){ pub fn run_ui(args: Vec<String>) {
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 native_options = eframe::NativeOptions { let native_options = eframe::NativeOptions {
+2
View File
@@ -1,6 +1,8 @@
use crate::platform::Platform; use crate::platform::Platform;
use std::error::Error; use std::error::Error;
#[cfg(target_os = "windows")]
use std::path::Path; use std::path::Path;
#[cfg(target_os = "windows")]
use std::path::PathBuf; use std::path::PathBuf;
use super::{game::Game, settings::UplaySettings}; use super::{game::Game, settings::UplaySettings};