diff --git a/TrimuiSmartHub.Application/App.xaml b/TrimuiSmartHub.Application/App.xaml index d97905f..5b7a837 100644 --- a/TrimuiSmartHub.Application/App.xaml +++ b/TrimuiSmartHub.Application/App.xaml @@ -49,8 +49,8 @@ - - + + diff --git a/TrimuiSmartHub.Application/Frames/GameDownloader.xaml b/TrimuiSmartHub.Application/Frames/GameDownloader.xaml new file mode 100644 index 0000000..461daa8 --- /dev/null +++ b/TrimuiSmartHub.Application/Frames/GameDownloader.xaml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/TrimuiSmartHub.Application/Frames/GameDownloader.xaml.cs b/TrimuiSmartHub.Application/Frames/GameDownloader.xaml.cs new file mode 100644 index 0000000..ae8c99d --- /dev/null +++ b/TrimuiSmartHub.Application/Frames/GameDownloader.xaml.cs @@ -0,0 +1,162 @@ +using System.IO; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using TrimuiSmartHub.Application.Repository; +using TrimuiSmartHub.Application.Services.LibRetro; +using TrimuiSmartHub.Application.Services.Trimui; +using TrimuiSmartHub.Application.Helpers; +using TrimuiSmartHub.Application.Services; +using CsQuery.Implementation; +using MahApps.Metro.Controls.Dialogs; +using MahApps.Metro.Controls; +using System.Linq; +using TrimuiSmartHub.Application.Pages; +using CsQuery.Engine.PseudoClassSelectors; + +namespace TrimuiSmartHub.Application.Frames +{ + public partial class GameDownloader : Page + { + private SmartProHub Parent { get; set; } + public GameDownloader(SmartProHub parent) + { + InitializeComponent(); + + Parent = parent; + + PopulateEmulators(); + } + + private void PopulateEmulators() + { + Task.Run(() => + { + var emulatorList = TrimuiService.New().GetEmulators(); + + foreach (var emulator in emulatorList) + { + + Dispatcher.Invoke(() => + { + var emulatorCard = CreateGameComponent(emulator); + + if (emulatorCard != null) + { + RomsContainer.Children.Add(emulatorCard); + } + }); + } + + Dispatcher.Invoke(() => + { + RomsPanel.Visibility = Visibility.Visible; + LoadingIndicator.Visibility = Visibility.Collapsed; + }); + }); + } + private Button? CreateGameComponent(string emulator) + { + string emulatorDescription; + + EmulatorDictionary.EmulatorMapRetrostic.TryGetValue(emulator, out emulatorDescription); + + if (emulatorDescription.IsNullOrEmpty()) return null; + + Border border = new Border + { + Background = new LinearGradientBrush + { + StartPoint = new Point(0.5, 0), + EndPoint = new Point(0.5, 1), + GradientStops = new GradientStopCollection + { + new GradientStop(Color.FromArgb(35, 25, 84, 112), 1), + new GradientStop(Color.FromArgb(75, 45, 84, 112), 1) + } + }, + CornerRadius = new CornerRadius(10), + Width = 120, + Height = 120, + Margin = new Thickness(5), + BorderThickness = new Thickness(1), + BorderBrush = new SolidColorBrush(Color.FromArgb(75, 45, 84, 112)), + }; + + StackPanel stackPanel = new StackPanel + { + Orientation = Orientation.Vertical, + VerticalAlignment = VerticalAlignment.Center, + HorizontalAlignment = HorizontalAlignment.Center + }; + + try + { + var imgSource = new BitmapImage(new Uri($"pack://application:,,,/Resources/Images/Emulators/{emulator}.png")); + Image image = new Image + { + Source = imgSource, + Width = 70, + Height = 60, + VerticalAlignment = VerticalAlignment.Center, + Margin = new Thickness(0, 0, 0, 0) + }; + + RenderOptions.SetBitmapScalingMode(image, BitmapScalingMode.HighQuality); + + stackPanel.Children.Add(image); + } + catch (Exception) + { + // + } + + + TextBlock titleBlock = new TextBlock + { + Text = emulator, + FontSize = 14, + FontWeight = FontWeights.Bold, + Foreground = Brushes.LightGray, + HorizontalAlignment = HorizontalAlignment.Center + }; + + stackPanel.Children.Add(titleBlock); + + border.Child = stackPanel; + + Button button = new Button + { + Content = border, + Style = (Style)System.Windows.Application.Current.FindResource("GameButtonStyle"), + Background = Brushes.Transparent, + BorderThickness = new Thickness(0), + }; + + button.Click += async (sender, e) => + { + //await Loading(true, $"Downloading games boxart..."); + + var count = 0; + + Task.Run(async () => + { + //var download = RetrosticService.New().DownloadGame(emulator, "Street Fighter"); + + Dispatcher.Invoke(() => + { + Parent.NavigationFrame.Navigate(new GameDownloaderSearch(emulator)); + }); + + }); + + //await Loading(false); + + //await ShowMessageAsync("Download Completed!", (count > 0) ? $"{count} Files was updated!" : "The boxarts already updated!"); + }; + + return button; + } + } +} diff --git a/TrimuiSmartHub.Application/Frames/GameDownloaderSearch.xaml b/TrimuiSmartHub.Application/Frames/GameDownloaderSearch.xaml new file mode 100644 index 0000000..9568a66 --- /dev/null +++ b/TrimuiSmartHub.Application/Frames/GameDownloaderSearch.xaml @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/TrimuiSmartHub.Application/Frames/GameDownloaderSearch.xaml.cs b/TrimuiSmartHub.Application/Frames/GameDownloaderSearch.xaml.cs new file mode 100644 index 0000000..d8e719e --- /dev/null +++ b/TrimuiSmartHub.Application/Frames/GameDownloaderSearch.xaml.cs @@ -0,0 +1,308 @@ +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media.Imaging; +using System.Windows.Media; +using TrimuiSmartHub.Application.Model; +using System.Windows.Data; +using System.Globalization; +using TrimuiSmartHub.Application.Services; +using System.Windows.Input; +using TrimuiSmartHub.Application.Repository; +using TrimuiSmartHub.Application.Helpers; +using System.Diagnostics; +using MahApps.Metro.Controls.Dialogs; +using MahApps.Metro.Controls; +using System.Runtime.CompilerServices; + +namespace TrimuiSmartHub.Application.Frames +{ + public class WidthAdjustmentConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value is double width) + { + // Subtrair 10 pixels da largura original + return width - 10; + } + return value; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } + public partial class GameDownloaderSearch : Page + { + private ProgressDialogController Controller { get; set; } + private List GameList { get; set; } + private string Emulator { get; set; } + public GameDownloaderSearch(string emulator) + { + InitializeComponent(); + + string emulatorDescription; + + EmulatorDictionary.EmulatorMapSystem.TryGetValue(emulator, out emulatorDescription); + + if (emulatorDescription.IsNotNullOrEmpty()) ConsoleName.Text = $"{emulatorDescription} Games"; + + Emulator = emulator; + + Task.Run(() => PopulateGameList(emulator)); + } + + private void PopulateGameList(string emulator) + { + Task.Run(async () => + { + var gameList = await RetrosticService.New().ListGamesByEmulator(emulator); + + if (gameList == null) return; + + GameList = gameList; + + foreach (var item in GameList) + { + Dispatcher.Invoke(() => + { + var button = CreateGameButton(item); + + Container.Children.Add(button); + }); + } + + Dispatcher.Invoke(() => + { + LoadingComponent.Visibility = Visibility.Collapsed; + Container.Visibility = Visibility.Visible; + }); + }); + } + + public Button CreateGameButton(GameInfoRetrostic gameInfo) + { + Button button = new Button + { + Margin = new Thickness(0, 10, 0, 0), + Style = (Style)System.Windows.Application.Current.FindResource("TransparentButton"), + Cursor = Cursors.Hand + }; + + Border border = new Border + { + BorderBrush = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#AAB8C2")), + BorderThickness = new Thickness(1), + CornerRadius = new CornerRadius(5), + Background = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#B31C2E41")), + Padding = new Thickness(10) + }; + + Grid grid = new Grid(); + grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto }); + grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(3, GridUnitType.Star) }); + grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) }); + + + try + { + var imgSrc = new BitmapImage(gameInfo.BoxArt); + Image image = new Image + { + Source = imgSrc, + Width = 100, + Height = 70, + VerticalAlignment = VerticalAlignment.Center + }; + Grid.SetColumn(image, 0); + + grid.Children.Add(image); + } + catch (Exception) + { + // + } + + TextBlock textBlock = new TextBlock + { + Text = gameInfo.Title, + Foreground = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#AAB8C2")), + FontWeight = FontWeights.SemiBold, + FontSize = 18, + VerticalAlignment = VerticalAlignment.Center, + Margin = new Thickness(50, 0, 0, 0) + }; + Grid.SetColumn(textBlock, 1); + + grid.Children.Add(textBlock); + + TextBlock textRegion = new TextBlock + { + Text = gameInfo.Region, + Foreground = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#AAB8C2")), + FontWeight = FontWeights.SemiBold, + FontSize = 18, + VerticalAlignment = VerticalAlignment.Center, + Margin = new Thickness(50, 0, 0, 0) + }; + Grid.SetColumn(textRegion, 2); + + grid.Children.Add(textRegion); + + Binding binding = new Binding("ActualWidth") + { + RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(WrapPanel), 1), + Converter = new WidthAdjustmentConverter() + }; + border.SetBinding(Border.WidthProperty, binding); + + border.Child = grid; + + button.Content = border; + + button.Click += async (sender, e) => + { + await Loading(true, $"Downloading {gameInfo.Title}"); + + await Task.Run(async () => + { + var (contentStream, fileStream, totalBytes) = await RetrosticService.New().DownloadGame(gameInfo); + + var buffer = new byte[8192]; + long totalBytesRead = 0; + int bytesRead; + var stopwatch = Stopwatch.StartNew(); + + Controller.Maximum = 100; + + while ((bytesRead = await contentStream.ReadAsync(buffer, 0, buffer.Length)) > 0) + { + await fileStream.WriteAsync(buffer, 0, bytesRead); + totalBytesRead += bytesRead; + + double elapsedTime = stopwatch.Elapsed.TotalSeconds; + + double downloadSpeed = totalBytesRead / elapsedTime; + + double downloadSpeedMbps = downloadSpeed / (1024 * 1024); + + double downloadSpeedKbps = downloadSpeed / 1024; + + Debug.WriteLine($"Downloaded {(double)totalBytesRead * 100 / totalBytes:0.00}%."); + + double progress = (totalBytesRead * 100 / totalBytes); + + progress = Math.Min(progress, 100); + + await Dispatcher.InvokeAsync(() => { + Controller.SetProgress(progress); + Controller.SetMessage($"Progress: {progress:0.00}% | Download Speed: {downloadSpeedMbps:0.00} MB/s"); + }); + } + + fileStream.Close(); + contentStream.Close(); + }); + + await Loading(false); + }; + + + return button; + } + + private async Task Loading(bool isLoading, string controllerTitle = null, Action cancelAction = null) + { + try + { + await CloseController(); + + if (!isLoading) return; + + var metroDialogSettings = new MetroDialogSettings + { + DialogTitleFontSize = 30, + DialogMessageFontSize = 20, + AnimateShow = true, + AnimateHide = true, + ColorScheme = MetroDialogColorScheme.Inverted + }; + + var metroWindow = (MetroWindow)System.Windows.Application.Current.MainWindow; + + controllerTitle = controllerTitle.IsNullOrEmpty() ? "Downloading box arts..." : controllerTitle; + + Controller = await metroWindow.ShowProgressAsync(controllerTitle, "Please don't disconnect the device.", cancelAction != null, metroDialogSettings); + + //Controller.SetIndeterminate(); + + Controller.Canceled += (sender, args) => + { + cancelAction?.Invoke(); + }; + } + catch (Exception) + { + await CloseController(); + } + } + + private async Task CloseController() + { + try + { + if (Controller != null) + { + if (Controller.IsOpen) await Controller.CloseAsync(); + + Controller = null; + } + } + catch (Exception) + { + // ignored + } + } + + private void Search_Button_Click(object sender, RoutedEventArgs e) + { + try + { + Container.Children.Clear(); + + LoadingComponent.Visibility = Visibility.Visible; + + Task.Run(async () => + { + var searchTerm = Dispatcher.Invoke(() => SearchTermTextBox.Text); + var gameList = await RetrosticService.New().SearchGamesByName(searchTerm, Emulator); + + if (gameList == null) return; + + GameList = gameList; + + foreach (var item in GameList) + { + Dispatcher.Invoke(() => + { + var button = CreateGameButton(item); + + Container.Children.Add(button); + }); + } + + Dispatcher.Invoke(() => + { + LoadingComponent.Visibility = Visibility.Collapsed; + Container.Visibility = Visibility.Visible; + }); + }); + } + catch (Exception) + { + // + } + } + } +} diff --git a/TrimuiSmartHub.Application/Frames/GameImageScrapper.xaml.cs b/TrimuiSmartHub.Application/Frames/GameImageScrapper.xaml.cs index 2983c85..673941b 100644 --- a/TrimuiSmartHub.Application/Frames/GameImageScrapper.xaml.cs +++ b/TrimuiSmartHub.Application/Frames/GameImageScrapper.xaml.cs @@ -132,20 +132,20 @@ private void PopulateEmulators() button.Click += async (sender, e) => { - var metroWindow = (MetroWindow)System.Windows.Application.Current.MainWindow; + await Loading(true, $"Downloading games boxart..."); - var imgFolder = TrimuiService.New().GetImageFolder(emulator); var count = 0; - var totalRoms = romsList.Count; - int processedRoms = 0; + await Task.Run(async () => + { + var imgFolder = await Task.Run(() => TrimuiService.New().GetImageFolder(emulator)); + + var totalRoms = romsList.Count; - var libRetro = LibretroService.New(); + int processedRoms = 0; - await Loading(true, $"Downloading games box art..."); + var libRetro = LibretroService.New(); - await Task.Run(async () => - { foreach (var romFile in romsList) { var rom = romFile.Split('.').First(); @@ -159,10 +159,7 @@ await Task.Run(async () => var boxImage = await libRetro.SearchThumbnail(emulatorDescription, romFile); - if (boxImage == null) - { - continue; - } + if (boxImage == null) continue; try { @@ -171,21 +168,19 @@ await Task.Run(async () => } catch (Exception ex) { - //ignore + continue; } } - }); - await Loading(false); - if (count > 0) await ShowMessageAsync("Download Completed!", $"{count} Files was updated!"); + await ShowMessageAsync("Download Completed!", (count > 0) ? $"{count} Files was updated!" : "The boxarts already updated!"); }; return button; } - private async Task ShowMessageAsync(string title, string content, MetroDialogSettings dialogSettings = null) + private static async Task ShowMessageAsync(string title, string content, MetroDialogSettings dialogSettings = null) { if (dialogSettings == null) { diff --git a/TrimuiSmartHub.Application/Helpers/ValidationHelper.cs b/TrimuiSmartHub.Application/Helpers/ValidationHelper.cs index 0d6b95f..37cf53f 100644 --- a/TrimuiSmartHub.Application/Helpers/ValidationHelper.cs +++ b/TrimuiSmartHub.Application/Helpers/ValidationHelper.cs @@ -215,6 +215,11 @@ public static string Clear(this string stringToClean) return stringToClean == null ? null : Regex.Replace(stringToClean, @"[^\d]", string.Empty); } + public static string ClearSpecial(this string stringToClean) + { + return stringToClean == null ? null : Regex.Replace(stringToClean, @"[^a-zA-Z0-9]", string.Empty); + } + public static bool IsNullOrEmpty(this string stringToVerify) { return string.IsNullOrEmpty(stringToVerify); diff --git a/TrimuiSmartHub.Application/MainWindow.xaml.cs b/TrimuiSmartHub.Application/MainWindow.xaml.cs index b8f8760..f75aa47 100644 --- a/TrimuiSmartHub.Application/MainWindow.xaml.cs +++ b/TrimuiSmartHub.Application/MainWindow.xaml.cs @@ -16,7 +16,7 @@ public MainWindow() { InitializeComponent(); - ThemeManager.Current.ChangeTheme(this, ThemeManager.Current.GetTheme("Light.Blue")); + ThemeManager.Current.ChangeTheme(this, ThemeManager.Current.GetTheme("Light.Steel")); trimuiService = TrimuiService.New(); diff --git a/TrimuiSmartHub.Application/Model/GameInfoRetrostic.cs b/TrimuiSmartHub.Application/Model/GameInfoRetrostic.cs new file mode 100644 index 0000000..0be11a2 --- /dev/null +++ b/TrimuiSmartHub.Application/Model/GameInfoRetrostic.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TrimuiSmartHub.Application.Model +{ + public class GameInfoRetrostic + { + public string? Emulator { get; set; } + public string Title { get; set; } + public Uri? BoxArt { get; set; } + public string? Region { get; set; } + public Uri? DownloadPage { get; set; } + } +} diff --git a/TrimuiSmartHub.Application/Pages/Home.xaml b/TrimuiSmartHub.Application/Pages/Home.xaml index b152fb5..03a8c15 100644 --- a/TrimuiSmartHub.Application/Pages/Home.xaml +++ b/TrimuiSmartHub.Application/Pages/Home.xaml @@ -92,7 +92,7 @@ - + diff --git a/TrimuiSmartHub.Application/Pages/SmartProHub.xaml b/TrimuiSmartHub.Application/Pages/SmartProHub.xaml index fe230e2..a3df6cc 100644 --- a/TrimuiSmartHub.Application/Pages/SmartProHub.xaml +++ b/TrimuiSmartHub.Application/Pages/SmartProHub.xaml @@ -29,8 +29,8 @@ -