Skip to content

Commit

Permalink
Refactor GameButtonFactory and MainWindow, add new SystemConfig
Browse files Browse the repository at this point in the history
GameButtonFactory has been refactored to improve image loading process by handling corrupted images with a fallback. In MainWindow.xaml.cs, redundant comments and dead code have been trimmed, improving readability. Additionally, support for game search functionality is now provided. The system.xml file was updated to include a new SystemConfig.
  • Loading branch information
drpetersonfernandes committed Mar 19, 2024
1 parent c4a2e8a commit 0ac3116
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 135 deletions.
82 changes: 55 additions & 27 deletions SimpleLauncher/GameButtonFactory.cs
Expand Up @@ -24,14 +24,13 @@ internal class GameButtonFactory(

// List to hold machine data
// Initialize _machines

private ComboBox EmulatorComboBox { get; set; } = emulatorComboBox;
private ComboBox SystemComboBox { get; set; } = systemComboBox;
private List<SystemConfig> SystemConfigs { get; set; } = systemConfigs;

public async Task<Button> CreateGameButtonAsync(string filePath, string systemName, SystemConfig systemConfig)
{
// Load Video Url and Info Url from settings (settings.xml)
// Load Video Url and Info Url from settings.xml
string videoUrl = settings.VideoUrl;
string infoUrl = settings.InfoUrl;

Expand All @@ -41,14 +40,6 @@ public async Task<Button> CreateGameButtonAsync(string filePath, string systemNa
string imagePath = DetermineImagePath(fileNameWithoutExtension, systemConfig.SystemName, systemConfig);
bool isDefaultImage = imagePath.EndsWith(DefaultImagePath);

var image = new Image
{
Height = ImageHeight,
HorizontalAlignment = HorizontalAlignment.Center
};

await LoadImageAsync(image, imagePath);

var textBlock = new TextBlock
{
Text = fileNameWithoutExtension,
Expand Down Expand Up @@ -112,7 +103,15 @@ public async Task<Button> CreateGameButtonAsync(string filePath, string systemNa
Margin = new Thickness(0),
Padding = new Thickness(0)
};

var image = new Image
{
Height = ImageHeight,
HorizontalAlignment = HorizontalAlignment.Center
};

await LoadImageAsync(image, button, imagePath, DefaultImagePath);

button.PreviewMouseLeftButtonDown += (_, args) =>
{
if (args.OriginalSource is Image img && (img.Name == "youtubeIcon" || img.Name == "infoIcon"))
Expand Down Expand Up @@ -167,36 +166,68 @@ private string DetermineImagePath(string fileNameWithoutExtension, string system
return Path.Combine(_baseDirectory, "images", DefaultImagePath);
}

private static async Task LoadImageAsync(Image imageControl, string imagePath)
private static async Task LoadImageAsync(Image imageControl, Button button, string imagePath, string defaultImagePath)
{
ArgumentNullException.ThrowIfNull(imageControl);

if (string.IsNullOrWhiteSpace(imagePath))
throw new ArgumentException(@"Invalid image path.", nameof(imagePath));
try
{
var bitmapImage = await Task.Run(() =>
{
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.CacheOption = BitmapCacheOption.OnLoad;
// Ensure the stream stays open until the BitmapImage is loaded
bi.StreamSource = File.OpenRead(imagePath);
bi.EndInit();
// Important for multi-threaded access
bi.Freeze();
return bi;
});

BitmapImage bitmapImage = null;
// Assign the loaded image to the image control on the UI thread
imageControl.Source = bitmapImage;
}
catch (Exception)
{
// If an exception occurs (e.g., the image is corrupt), load a default image
// This uses the dispatcher to ensure UI elements are accessed on the UI thread
imageControl.Dispatcher.Invoke(() => LoadFallbackImage(imageControl, button, defaultImagePath));
MessageBox.Show($"Unable to load image: {Path.GetFileName(imagePath)}.\nThis image is corrupted!\nA default image will be displayed instead.", "Image Loading Error", MessageBoxButton.OK, MessageBoxImage.Warning);
}
}

await Task.Run(() =>
private static void LoadFallbackImage(Image imageControl, Button button, string defaultImagePath)
{
string fallbackImagePath = defaultImagePath;

// If the specific default image doesn't exist, try the global default image
if (!File.Exists(fallbackImagePath))
{
using var stream = File.OpenRead(imagePath);
bitmapImage = new BitmapImage();
fallbackImagePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "images", DefaultImagePath);
}

if (File.Exists(fallbackImagePath))
{
var bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.UriSource = new Uri(fallbackImagePath, UriKind.Absolute);
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.StreamSource = stream;
bitmapImage.EndInit();
bitmapImage.Freeze(); // Important for multi-threaded access
});

// Update the UI thread with the loaded image
if (bitmapImage != null)
imageControl.Source = bitmapImage; // Assign the fallback image
button.Tag = "DefaultImage"; // Tagging the button to indicate a default image is used
}
else
{
imageControl.Dispatcher.Invoke(() =>
{
imageControl.Source = bitmapImage;
});
// If even the global default image is not found, handle accordingly
MessageBox.Show("No valid default image found.", "Image Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
}


private Image CreateYoutubeIcon(string fileNameWithoutExtension, string systemName, string videoUrl)
{
var youtubeIcon = new Image
Expand Down Expand Up @@ -275,11 +306,8 @@ private Image CreateInfoIcon(string fileNameWithoutExtension, string systemName,
MainWindow.HandleError(exception, "The URL provided for Info Link did not work.\nPlease update the Info Link in the Edit Links menu.");
throw;
}
e.Handled = true; // Stops the click event from propagating to the button's main click event
};

return infoIcon;
}

Expand Down
180 changes: 72 additions & 108 deletions SimpleLauncher/MainWindow.xaml.cs
Expand Up @@ -53,14 +53,13 @@ public MainWindow()
Application.Current.Shutdown();
}

// Apply settings to your application
// HideGamesNoCover.IsChecked = _settings.HideGamesWithNoCover;
// Apply settings to application from settings.xml
EnableGamePadNavigation.IsChecked = _settings.EnableGamePadNavigation;
UpdateMenuCheckMarks(_settings.ThumbnailSize);
UpdateMenuCheckMarks2(_settings.GamesPerPage);
UpdateMenuCheckMarks3(_settings.ShowGames);
_filesPerPage = _settings.GamesPerPage; // load GamesPerPage value from setting.xml
_paginationThreshold = _settings.GamesPerPage; // load GamesPerPage value from setting.xml
_filesPerPage = _settings.GamesPerPage;
_paginationThreshold = _settings.GamesPerPage;

// Initialize the GamePadController.cs
// Setting the error logger
Expand All @@ -79,10 +78,7 @@ public MainWindow()
// Initialize _gameFileGrid
_gameFileGrid = FindName("GameFileGrid") as WrapPanel;

// // Add the StackPanel from LetterNumberMenu to the MainWindow's Grid
// Grid.SetRow(_letterNumberMenu.LetterPanel, 1);
// ((Grid)Content).Children.Add(_letterNumberMenu.LetterPanel);

// Add the StackPanel from LetterNumberMenu to the MainWindow's Grid
// Initialize LetterNumberMenu and add it to the UI
_letterNumberMenu = new LetterNumberMenu();
LetterNumberMenu.Children.Clear(); // Clear if necessary
Expand Down Expand Up @@ -494,6 +490,74 @@ public static async void HandleError(Exception ex, string message)
_ = new LogErrors();
await LogErrors.LogErrorAsync(ex, message);
}

private async void SearchButton_Click(object sender, RoutedEventArgs e)
{
// Reset pagination controls
ResetPaginationButtons();

var searchQuery = SearchTextBox.Text.Trim();

if (SystemComboBox.SelectedItem == null)
{
MessageBox.Show("Please select a system before searching.", "System Not Selected", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}

if (string.IsNullOrEmpty(searchQuery))
{
MessageBox.Show("Please enter a search query.", "Search Query Required", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}

// Show the "Please Wait" window
var pleaseWaitWindow = new PleaseWaitWindow();
pleaseWaitWindow.Show();

try
{
await LoadGameFiles(searchQuery: searchQuery);
}
finally
{
// Close the "Please Wait" window
pleaseWaitWindow.Close();
}
}

private async void SearchTextBox_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
var searchQuery = SearchTextBox.Text.Trim();

if (SystemComboBox.SelectedItem == null)
{
MessageBox.Show("Please select a system before searching.", "System Not Selected", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}

if (string.IsNullOrEmpty(searchQuery))
{
MessageBox.Show("Please enter a search query.", "Search Query Required", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}

// Show the "Please Wait" window
var pleaseWaitWindow = new PleaseWaitWindow();
pleaseWaitWindow.Show();

try
{
await LoadGameFiles(searchQuery: searchQuery);
}
finally
{
// Close the "Please Wait" window
pleaseWaitWindow.Close();
}
}
}

#region Menu Items

Expand Down Expand Up @@ -547,39 +611,6 @@ private void Exit_Click(object sender, RoutedEventArgs e)
{
Close();
}

// private void HideGamesNoCover_Click(object sender, RoutedEventArgs e)
// {
// if (sender is MenuItem menuItem)
// {
// menuItem.IsChecked = !menuItem.IsChecked;
// _settings.HideGamesWithNoCover = menuItem.IsChecked;
// _settings.Save();
//
// // Hide games with no cover
// if (menuItem.IsChecked)
// {
// foreach (var child in _gameFileGrid.Children)
// {
// if (child is Button btn && btn.Tag?.ToString() == "DefaultImage")
// {
// btn.Visibility = Visibility.Collapsed; // Hide the button
// }
// }
// }
// else
// {
// // Show all games
// foreach (var child in _gameFileGrid.Children)
// {
// if (child is Button btn)
// {
// btn.Visibility = Visibility.Visible; // Show the button
// }
// }
// }
// }
// }

private void ShowAllGames_Click(object sender, RoutedEventArgs e)
{
Expand Down Expand Up @@ -684,73 +715,6 @@ private void GamesPerPage_Click(object sender, RoutedEventArgs e)
}

#endregion

private async void SearchButton_Click(object sender, RoutedEventArgs e)
{
var searchQuery = SearchTextBox.Text.Trim();

if (SystemComboBox.SelectedItem == null)
{
MessageBox.Show("Please select a system before searching.", "System Not Selected", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}

if (string.IsNullOrEmpty(searchQuery))
{
MessageBox.Show("Please enter a search query.", "Search Query Required", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}

// Show the "Please Wait" window
var pleaseWaitWindow = new PleaseWaitWindow();
pleaseWaitWindow.Show();

try
{
await LoadGameFiles(searchQuery: searchQuery);
}
finally
{
// Close the "Please Wait" window
pleaseWaitWindow.Close();
}
}

private async void SearchTextBox_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
var searchQuery = SearchTextBox.Text.Trim();

if (SystemComboBox.SelectedItem == null)
{
MessageBox.Show("Please select a system before searching.", "System Not Selected", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}

if (string.IsNullOrEmpty(searchQuery))
{
MessageBox.Show("Please enter a search query.", "Search Query Required", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}

// Show the "Please Wait" window
var pleaseWaitWindow = new PleaseWaitWindow();
pleaseWaitWindow.Show();

try
{
await LoadGameFiles(searchQuery: searchQuery);
}
finally
{
// Close the "Please Wait" window
pleaseWaitWindow.Close();
}
}
}



}
}
20 changes: 20 additions & 0 deletions SimpleLauncher/system.xml
Expand Up @@ -1938,4 +1938,24 @@
</Emulator>
</Emulators>
</SystemConfig>
<SystemConfig>
<SystemName>Test</SystemName>
<SystemFolder>C:\Test</SystemFolder>
<SystemImageFolder>C:\Test\images</SystemImageFolder>
<SystemIsMAME>false</SystemIsMAME>
<FileFormatsToSearch>
<FormatToSearch>zip</FormatToSearch>
</FileFormatsToSearch>
<ExtractFileBeforeLaunch>false</ExtractFileBeforeLaunch>
<FileFormatsToLaunch>
<FormatToLaunch></FormatToLaunch>
</FileFormatsToLaunch>
<Emulators>
<Emulator>
<EmulatorName>Retroarch ppsspp</EmulatorName>
<EmulatorLocation>D:\Emulators\RetroArch\retroarch.exe</EmulatorLocation>
<EmulatorParameters>-L "D:\Emulators\RetroArch\cores\ppsspp_libretro.dll" -c "D:\Emulators\RetroArch\Config.cfg" -f</EmulatorParameters>
</Emulator>
</Emulators>
</SystemConfig>
</SystemConfigs>

0 comments on commit 0ac3116

Please sign in to comment.