Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
d4c10c1
Added basic Auth with tokens
Yelo420 Mar 25, 2025
ea751f7
OAuth base + fallback ludusavi search title
Yelo420 Mar 27, 2025
c63c441
Multiple Profiles base
Yelo420 Apr 6, 2025
a786634
Added basic logout + remember me
Yelo420 Apr 14, 2025
27177f4
Fixed Theme loading
Yelo420 Apr 15, 2025
903963e
Added OAuth Login + integrated the database backup restore control in…
Yelo420 Apr 19, 2025
8430c5c
Added base sign up + prepared parts of the app protocol for multi pro…
Yelo420 Apr 19, 2025
dfd88a5
Excluded deleted users from community tab
Yelo420 Apr 19, 2025
fa64de5
Baerer Auth auto relogin from offline mode + smoother OAuth window ha…
Yelo420 Apr 20, 2025
3d82414
Bug fix: Reset Library Filter will now include developer and publishe…
Yelo420 Apr 20, 2025
6ae3a4a
Extreme performance improvement of the cache optimizer + Bug fix: Use…
Yelo420 Apr 20, 2025
fc73a39
Fixed token refresh check
Yelo420 Apr 20, 2025
781b79e
Login window close will always be a shutdown
Yelo420 May 7, 2025
dcc9fb7
Fixed background start + fixed Analytics
Yelo420 May 7, 2025
c918462
Added NotActivated status code + added wait for activated with login …
Yelo420 May 8, 2025
1a1af19
Added skeleton loading animation for user loading in the communuty tab
Yelo420 May 8, 2025
7ee8cb8
Added multi root directories
Yelo420 May 13, 2025
a4628ab
Fixed root directories UI not refreshing on user change
Yelo420 May 13, 2025
9cd9042
Added Logout button to basic auth
Yelo420 May 16, 2025
7a6d1f9
Removed protocoll string from server profile + fixed CLI install loca…
Yelo420 Jun 5, 2025
2c100d6
Installed games will now be restored on adding/removing a root direct…
Yelo420 Jun 5, 2025
2c9d958
Bug fix: Crash on DeleteUserProfile after canceling OAuth Login + Cac…
Yelo420 Jun 6, 2025
99f09bb
updated changelog
Yelo420 Jun 6, 2025
733c3fa
Bug fix: Savegame restore was not yet connected to the new authentica…
Yelo420 Jun 12, 2025
6540ec2
Added PendingActivation for login
Yelo420 Jun 14, 2025
da9463f
Added new filter for early access for file and metadata at the same t…
Yelo420 Jun 15, 2025
eae1a7e
Bug fix: Ensures profile file tree on every login
Yelo420 Jun 15, 2025
80db6b7
Cloud Saves - Add root path to generated config.yaml
Yelo420 Jun 15, 2025
3b2d56d
OAuth flow tries to reuse the refresh token, before opening a new ses…
Yelo420 Jun 16, 2025
f07b04f
Offline cache will be renewed if outdated
Yelo420 Jun 16, 2025
9b80fac
You can now see available Updates in the Library
Yelo420 Jun 16, 2025
e99c0d9
Bug fix: Override Credentials on user change
Yelo420 Jun 16, 2025
2c550d0
add analytics
Alfagun74 Jun 17, 2025
82b04e5
New Default Installer/Uninstaller and Uninstaller Settings
Yelo420 Jun 17, 2025
e7eac6d
Merge branch 'develop' of https://github.com/Phalcode/gamevault-app i…
Yelo420 Jun 17, 2025
9a94163
Added Go to Game buttion after successful installation
Yelo420 Jun 17, 2025
b9b77c6
Bug fix: Redownloaded installed game instead of starting it on coldstart
Yelo420 Jun 17, 2025
cd466fc
Bug fix: Downloaded games were shown as paused after downloading larg…
Yelo420 Jun 17, 2025
9b494e7
Finished logout from this device and logout from all devices
Yelo420 Jun 18, 2025
cb582eb
Dynamic view for the SignIn/SignUp by the configuration of /status api
Yelo420 Jun 19, 2025
81349f9
Fixed changed doku helper links
Yelo420 Jun 19, 2025
9d6ce99
Added additional request headers
Yelo420 Jun 20, 2025
691402d
Build temporary offline cache if not exists
Yelo420 Jun 20, 2025
a9b5b73
Legacy cache will be archived
Yelo420 Jun 20, 2025
77b7ffa
apend
Yelo420 Jun 20, 2025
cc5253a
Amend
Yelo420 Jun 20, 2025
fe1fabc
- Bug fix: Fixed an issue where the current user's profile data was o…
Yelo420 Jul 5, 2025
eec4140
Moved server outdated check to ogin window + added enter key to login…
Yelo420 Jul 16, 2025
fa3c957
Better Error Handling in Login/Registration URL Input
Yelo420 Jul 19, 2025
7d56dd1
You can now save profile without login
Yelo420 Jul 19, 2025
d94ad97
Migration of legacy user
Yelo420 Jul 19, 2025
7fba4d0
Added Copy API key button to user settings
Yelo420 Jul 20, 2025
7135024
Fixed game install duplicate not showed correctly by the message.
Yelo420 Jul 22, 2025
75ecc5f
Buf fix: server messages are fetched and displayed correctly
Yelo420 Jul 24, 2025
f4c1f76
Bug fix: Ongoing library serach requests will be cancelled if new sea…
Yelo420 Jul 27, 2025
6db09f0
Updated changelog and package versions
Yelo420 Jul 30, 2025
f28d02e
Changed EA to release
Yelo420 Aug 1, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,31 @@
# GameVault App Changelog

## 1.17.0
Recommended Gamevault Server Version: `v15.0.0`
### Changes

- Replaced setup wizard with a new login window
- Introduced multi-profile support: if no user profile is configured, the demo user is used by default
- Login window now dynamically adapts to the server configuration
- Upgraded all connections to use OAuth 2.0 authentication flow
- Added support for login and registration via configured identity providers (SSO)
- Implemented pending activation state in the login process
- Added options for logout from this device and logout from all devices
- Introduced support for multiple root directories, including selection during download
- Improved image cache performance
- Added support for additional request headers
- New game settings: default parameters for Un/Installer
- Cloud Saves: root path is now included in the generated config.yaml
- Offline cache now auto-renews when outdated
- Added visual indicator on the install game card when an update is available
- Implemented skeleton loading animations in the community tab to better indicate loading states
- Added "Go to Game" button after installation is complete
- Pressing F5 in the Library now also refreshes the list of installed games
- Build temporary offline cache if it does not exist, so that you can still see your installed games in offline mode even if you have deleted the offline cache or it is corrupted.
- Copy button for own users API key in the user settings
- Bug fix: extraction time remaining now displays correctly
- Bug fix: Duplicate entries when typing in the library search

## 1.16.1
Recommended Gamevault Server Version: `v14.1.0`
### Changes
Expand Down
133 changes: 53 additions & 80 deletions gamevault/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,76 +43,65 @@ public static App Instance
}
}
#endregion
public static bool ShowToastMessage = true;
public static bool HideToSystemTray = true;
public static bool IsWindowsPackage = false;

public static CommandOptions? CommandLineOptions { get; internal set; } = null;

private NotifyIcon m_Icon;
private JumpList jumpList;

private GameTimeTracker m_gameTimeTracker;


protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
AnalyticsHelper.Instance.InitHeartBeat();
AnalyticsHelper.Instance.RegisterGlobalEvents();
AnalyticsHelper.Instance.SendCustomEvent(CustomAnalyticsEventKeys.APP_INITIALIZED, AnalyticsHelper.Instance.GetSysInfo());
AnalyticsHelper.Instance.SendCustomEvent(CustomAnalyticsEventKeys.APP_INITIALIZED, AnalyticsHelper.Instance.GetSysInfo());
}

private async void Application_Startup(object sender, StartupEventArgs e)
{
Application.Current.DispatcherUnhandledException += new DispatcherUnhandledExceptionEventHandler(AppDispatcherUnhandledException);
#if DEBUG
AppFilePath.InitDebugPaths();
CreateDirectories();
RestoreTheme();
await CacheHelper.OptimizeCache();
#else

try
{
CreateDirectories();
RestoreTheme();
UpdateWindow updateWindow = new UpdateWindow();
updateWindow.ShowDialog();
LoginWindow loginWindow = new LoginWindow();
bool? result = loginWindow.ShowDialog();
if (result == null || result == false)
Shutdown();
loginWindow = null;
#if WINDOWS
InitNotifyIcon();
InitJumpList();
#endif
}
catch (Exception ex)
{
LogUnhandledException(ex);
//m_StoreHelper.NoInternetException();
}
#endif
await LoginManager.Instance.StartupLogin();
await LoginManager.Instance.PhalcodeLogin(true);

AnalyticsHelper.Instance.SendCustomEvent(CustomAnalyticsEventKeys.USER_SETTINGS, AnalyticsHelper.Instance.PrepareSettingsForAnalytics());

m_gameTimeTracker = new GameTimeTracker();
await m_gameTimeTracker.Start();
//AnalyticsHelper.Instance.SendCustomEvent(CustomAnalyticsEventKeys.USER_SETTINGS, AnalyticsHelper.Instance.PrepareSettingsForAnalytics());

bool startMinimizedByPreferences = false;
bool startMinimizedByCLI = false;
// bool startMinimizedByPreferences = false;
// bool startMinimizedByCLI = false;

if ((CommandLineOptions?.Minimized).HasValue)
startMinimizedByCLI = CommandLineOptions!.Minimized!.Value;
else if (SettingsViewModel.Instance.BackgroundStart)
startMinimizedByPreferences = true;
// if ((CommandLineOptions?.Minimized).HasValue)
// startMinimizedByCLI = CommandLineOptions!.Minimized!.Value;
// else if (SettingsViewModel.Instance.BackgroundStart)
// startMinimizedByPreferences = true;

if (!startMinimizedByPreferences && MainWindow == null)
{
MainWindow = new MainWindow();
MainWindow.Show();
}
if (startMinimizedByCLI && MainWindow != null)
{
MainWindow.Hide();
}
#if WINDOWS
InitNotifyIcon();
InitJumpList();
#endif
// After the app is created and most things are instantiated, handle any special command line stuff
// if (!startMinimizedByPreferences && MainWindow == null)
// {
// MainWindow = new MainWindow();
// MainWindow.Show();
// }
// if (startMinimizedByCLI && MainWindow != null)
// {
// MainWindow.Hide();
// }
// // After the app is created and most things are instantiated, handle any special command line stuff
if (PipeServiceHandler.Instance != null)
{
// Strictly speaking we should hold up all commands until we have a confirmed login & setup is complete, but for now we'll assume that auto-login has worked
Expand All @@ -136,10 +125,10 @@ public void LogUnhandledException(Exception e)
Application.Current.DispatcherUnhandledException -= new DispatcherUnhandledExceptionEventHandler(AppDispatcherUnhandledException);
string errorMessage = $"MESSAGE:\n{e.Message}\nINNER_EXCEPTION:{(e.InnerException != null ? "" + e.InnerException.Message : null)}";
string errorStackTrace = $"STACK_TRACE:\n{(e.StackTrace != null ? "" + e.StackTrace : null)}";
string errorLogPath = $"{AppFilePath.ErrorLog}\\GameVault_ErrorLog_{DateTime.Now.ToString("yyyyMMddHHmmssfff")}.txt";
string errorLogPath = $"{ProfileManager.ErrorLogDir}\\GameVault_ErrorLog_{DateTime.Now.ToString("yyyyMMddHHmmssfff")}.txt";
if (!File.Exists(errorLogPath))
{
Directory.CreateDirectory(AppFilePath.ErrorLog);
Directory.CreateDirectory(ProfileManager.ErrorLogDir);
File.Create(errorLogPath).Close();
}
File.WriteAllText(errorLogPath, errorMessage + "\n" + errorStackTrace);
Expand Down Expand Up @@ -189,6 +178,7 @@ public void SetJumpListGames()
{
try
{
jumpList.JumpItems.RemoveRange(5, jumpList.JumpItems.Count - 5);// Remove all previous games. Now we add the current game list
var lastGames = InstallViewModel.Instance.InstalledGames.Take(5).ToArray();
foreach (var game in lastGames)
{
Expand All @@ -210,31 +200,22 @@ public void SetJumpListGames()
}
catch { }
}
private void RestoreTheme()
public void ResetJumpListGames()
{
try
{
string currentThemeString = Preferences.Get(AppConfigKey.Theme, AppFilePath.UserFile, true);
if (currentThemeString != string.Empty)
{
ThemeItem currentTheme = JsonSerializer.Deserialize<ThemeItem>(currentThemeString)!;

if (App.Current.Resources.MergedDictionaries[0].Source.OriginalString != currentTheme.Path)
{
App.Current.Resources.MergedDictionaries[0] = new ResourceDictionary() { Source = new Uri(currentTheme.Path) };
}
}
jumpList.JumpItems.RemoveRange(5, jumpList.JumpItems.Count - 5);
jumpList.Apply();
}
catch { }
}
private void NotifyIcon_DoubleClick(Object sender, EventArgs e)
{
if (MainWindow == null)
{
MainWindow = new MainWindow();
MainWindow.Show();
}
else if (MainWindow.IsVisible == false)

if (MainWindow == null || MainWindow.GetType() != typeof(MainWindow))
return;

if (MainWindow.IsVisible == false)
{
MainWindow.Show();
}
Expand All @@ -244,6 +225,16 @@ private void NotifyIcon_DoubleClick(Object sender, EventArgs e)
}
}

public void SetTheme(string themeUri)
{
App.Current.Resources.MergedDictionaries[0] = new ResourceDictionary() { Source = new Uri(themeUri) };
App.Current.Resources.MergedDictionaries[1] = new ResourceDictionary() { Source = new Uri("pack://application:,,,/gamevault;component/Resources/Assets/Base.xaml") };
}
public void ResetToDefaultTheme()
{
App.Current.Resources.MergedDictionaries[0] = new ResourceDictionary() { Source = new Uri("pack://application:,,,/gamevault;component/Resources/Assets/Themes/ThemeDefaultDark.xaml") };
App.Current.Resources.MergedDictionaries[1] = new ResourceDictionary() { Source = new Uri("pack://application:,,,/gamevault;component/Resources/Assets/Base.xaml") };
}
private async void NotifyIcon_Exit_Click(Object sender, EventArgs e)
{
await ExitApp();
Expand Down Expand Up @@ -283,7 +274,7 @@ private void Navigate_Tab_Click(Object sender, EventArgs e)

private void ShutdownApp()
{
ShowToastMessage = false;
HideToSystemTray = false;
ProcessShepherd.Instance.KillAllChildProcesses();
if (m_Icon != null)
{
Expand All @@ -292,31 +283,13 @@ private void ShutdownApp()
}
Shutdown();
}
private void CreateDirectories()
{
if (!Directory.Exists(AppFilePath.ImageCache))
{
Directory.CreateDirectory(AppFilePath.ImageCache);
}
if (!Directory.Exists(AppFilePath.ConfigDir))
{
Directory.CreateDirectory(AppFilePath.ConfigDir);
}
if (!Directory.Exists(AppFilePath.ThemesLoadDir))
{
Directory.CreateDirectory(AppFilePath.ThemesLoadDir);
}
if (!Directory.Exists(AppFilePath.CloudSaveConfigDir))
{
Directory.CreateDirectory(AppFilePath.CloudSaveConfigDir);
}
}
public bool IsWindowActiveAndControlInFocus(MainControl control)
{
if (Current.MainWindow == null)
return false;

return Current.MainWindow.IsActive && MainWindowViewModel.Instance.ActiveControlIndex == (int)control;
}

}
}
2 changes: 1 addition & 1 deletion gamevault/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
[assembly: AssemblyVersion("1.16.1.0")]
[assembly: AssemblyVersion("1.17.0.0")]
[assembly: AssemblyCopyright("© Phalcode™. All Rights Reserved.")]
#if DEBUG
[assembly: XmlnsDefinition("debug-mode", "Namespace")]
Expand Down
23 changes: 23 additions & 0 deletions gamevault/Converter/BoolToVisibilityConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;

namespace gamevault.Converter
{
class BoolToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (bool)value ? System.Windows.Visibility.Visible : System.Windows.Visibility.Collapsed;
}

public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return null;
}
}
}
42 changes: 42 additions & 0 deletions gamevault/Converter/GameUpdateAvailableConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using gamevault.Models;
using gamevault.ViewModels;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;

namespace gamevault.Converter
{
internal class GameUpdateAvailableConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
try
{
Game game = (Game)value;
KeyValuePair<Game, string> result = InstallViewModel.Instance.InstalledGames.Where(g => g.Key.ID == game.ID).FirstOrDefault();
string execFile = Path.Combine(result.Value, "gamevault-exec");
string installedVersion = Preferences.Get(AppConfigKey.InstalledGameVersion, execFile);
if(string.IsNullOrWhiteSpace(installedVersion))
{
Preferences.Set(AppConfigKey.InstalledGameVersion, game.Version, execFile);
}
else if (installedVersion != game.Version)
{
return true;
}
}
catch { }
return false;
}

public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return null;
}
}
}
5 changes: 3 additions & 2 deletions gamevault/Converter/ShowMappedTitleConverter.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using gamevault.Models;
using gamevault.Helper;
using gamevault.Models;
using System;
using System.Collections.Generic;
using System.Globalization;
Expand All @@ -14,7 +15,7 @@ public class ShowMappedTitleConverter : IValueConverter
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{

bool showMappedTitle = Preferences.Get(AppConfigKey.ShowMappedTitle, AppFilePath.UserFile) == "1";
bool showMappedTitle = Preferences.Get(AppConfigKey.ShowMappedTitle,LoginManager.Instance.GetUserProfile().UserConfigFile) == "1";
if (showMappedTitle && value is Game game && !string.IsNullOrWhiteSpace(game?.Metadata?.Title))
{
return true;
Expand Down
Loading
Loading