mirror of
https://github.com/claunia/marechai.git
synced 2025-12-16 19:14:25 +00:00
Add GPU details page.
This commit is contained in:
@@ -14,6 +14,7 @@ using Uno.UI;
|
|||||||
using CompanyDetailViewModel = Marechai.App.Presentation.ViewModels.CompanyDetailViewModel;
|
using CompanyDetailViewModel = Marechai.App.Presentation.ViewModels.CompanyDetailViewModel;
|
||||||
using ComputersListViewModel = Marechai.App.Presentation.ViewModels.ComputersListViewModel;
|
using ComputersListViewModel = Marechai.App.Presentation.ViewModels.ComputersListViewModel;
|
||||||
using ComputersViewModel = Marechai.App.Presentation.ViewModels.ComputersViewModel;
|
using ComputersViewModel = Marechai.App.Presentation.ViewModels.ComputersViewModel;
|
||||||
|
using GpuDetailViewModel = Marechai.App.Presentation.ViewModels.GpuDetailViewModel;
|
||||||
using GpuListViewModel = Marechai.App.Presentation.ViewModels.GpusListViewModel;
|
using GpuListViewModel = Marechai.App.Presentation.ViewModels.GpusListViewModel;
|
||||||
using MachineViewViewModel = Marechai.App.Presentation.ViewModels.MachineViewViewModel;
|
using MachineViewViewModel = Marechai.App.Presentation.ViewModels.MachineViewViewModel;
|
||||||
using MainViewModel = Marechai.App.Presentation.ViewModels.MainViewModel;
|
using MainViewModel = Marechai.App.Presentation.ViewModels.MainViewModel;
|
||||||
@@ -137,6 +138,7 @@ public partial class App : Application
|
|||||||
services.AddTransient<ComputersListViewModel>();
|
services.AddTransient<ComputersListViewModel>();
|
||||||
services.AddTransient<ConsolesListViewModel>();
|
services.AddTransient<ConsolesListViewModel>();
|
||||||
services.AddTransient<GpuListViewModel>();
|
services.AddTransient<GpuListViewModel>();
|
||||||
|
services.AddTransient<GpuDetailViewModel>();
|
||||||
})
|
})
|
||||||
.UseNavigation(RegisterRoutes));
|
.UseNavigation(RegisterRoutes));
|
||||||
|
|
||||||
@@ -164,6 +166,7 @@ public partial class App : Application
|
|||||||
new ViewMap<MachineViewPage, MachineViewViewModel>(),
|
new ViewMap<MachineViewPage, MachineViewViewModel>(),
|
||||||
new ViewMap<PhotoDetailPage, PhotoDetailViewModel>(),
|
new ViewMap<PhotoDetailPage, PhotoDetailViewModel>(),
|
||||||
new ViewMap<GpuListPage, GpuListViewModel>(),
|
new ViewMap<GpuListPage, GpuListViewModel>(),
|
||||||
|
new ViewMap<GpuDetailPage, GpuDetailViewModel>(),
|
||||||
new DataViewMap<SecondPage, SecondViewModel, Entity>());
|
new DataViewMap<SecondPage, SecondViewModel, Entity>());
|
||||||
|
|
||||||
routes.Register(new RouteMap("",
|
routes.Register(new RouteMap("",
|
||||||
@@ -201,7 +204,7 @@ public partial class App : Application
|
|||||||
views.FindByViewModel<CompaniesViewModel>(),
|
views.FindByViewModel<CompaniesViewModel>(),
|
||||||
Nested:
|
Nested:
|
||||||
[
|
[
|
||||||
new RouteMap("detail",
|
new RouteMap("company-details",
|
||||||
views.FindByViewModel<
|
views.FindByViewModel<
|
||||||
CompanyDetailViewModel>())
|
CompanyDetailViewModel>())
|
||||||
]),
|
]),
|
||||||
@@ -209,10 +212,9 @@ public partial class App : Application
|
|||||||
views.FindByViewModel<GpuListViewModel>(),
|
views.FindByViewModel<GpuListViewModel>(),
|
||||||
Nested:
|
Nested:
|
||||||
[
|
[
|
||||||
new RouteMap("list-gpus",
|
new RouteMap("gpu-details",
|
||||||
views.FindByViewModel<
|
views.FindByViewModel<
|
||||||
GpuListViewModel>(),
|
GpuDetailViewModel>())
|
||||||
true)
|
|
||||||
]),
|
]),
|
||||||
new RouteMap("Second",
|
new RouteMap("Second",
|
||||||
views.FindByViewModel<SecondViewModel>())
|
views.FindByViewModel<SecondViewModel>())
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
// MARECHAI: Master repository of computing history artifacts information
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||||
|
//
|
||||||
|
// --[ License ] --------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation, either version 3 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
//
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Copyright © 2003-2026 Natalia Portillo
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
namespace Marechai.App.Presentation.Models;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Navigation parameter for the GpuDetailPage containing both the GPU ID and the navigation source.
|
||||||
|
/// </summary>
|
||||||
|
public class GpuDetailNavigationParameter
|
||||||
|
{
|
||||||
|
public required int GpuId { get; init; }
|
||||||
|
public object? NavigationSource { get; init; }
|
||||||
|
}
|
||||||
386
Marechai.App/Presentation/ViewModels/GpuDetailViewModel.cs
Normal file
386
Marechai.App/Presentation/ViewModels/GpuDetailViewModel.cs
Normal file
@@ -0,0 +1,386 @@
|
|||||||
|
#nullable enable
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using Marechai.App.Presentation.Models;
|
||||||
|
using Marechai.App.Services;
|
||||||
|
using Uno.Extensions.Navigation;
|
||||||
|
|
||||||
|
namespace Marechai.App.Presentation.ViewModels;
|
||||||
|
|
||||||
|
public partial class GpuDetailViewModel : ObservableObject
|
||||||
|
{
|
||||||
|
private readonly CompaniesService _companiesService;
|
||||||
|
private readonly GpusService _gpusService;
|
||||||
|
private readonly IStringLocalizer _localizer;
|
||||||
|
private readonly ILogger<GpuDetailViewModel> _logger;
|
||||||
|
private readonly INavigator _navigator;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private ObservableCollection<MachineItem> _computers = [];
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _computersFilterText = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _consoelsFilterText = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private ObservableCollection<MachineItem> _consoles = [];
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _errorMessage = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private ObservableCollection<MachineItem> _filteredComputers = [];
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private ObservableCollection<MachineItem> _filteredConsoles = [];
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private GpuDto? _gpu;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private int _gpuId;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool _hasComputers;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool _hasConsoles;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool _hasError;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool _isDataLoaded;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool _isLoading;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _manufacturerName = string.Empty;
|
||||||
|
private object? _navigationSource;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private ObservableCollection<ResolutionItem> _resolutions = [];
|
||||||
|
|
||||||
|
public GpuDetailViewModel(GpusService gpusService, CompaniesService companiesService, IStringLocalizer localizer,
|
||||||
|
ILogger<GpuDetailViewModel> logger, INavigator navigator)
|
||||||
|
{
|
||||||
|
_gpusService = gpusService;
|
||||||
|
_companiesService = companiesService;
|
||||||
|
_localizer = localizer;
|
||||||
|
_logger = logger;
|
||||||
|
_navigator = navigator;
|
||||||
|
LoadData = new AsyncRelayCommand(LoadDataAsync);
|
||||||
|
GoBackCommand = new AsyncRelayCommand(GoBackAsync);
|
||||||
|
SelectMachineCommand = new AsyncRelayCommand<int>(SelectMachineAsync);
|
||||||
|
ComputersFilterCommand = new RelayCommand(() => FilterComputers());
|
||||||
|
ConsolesFilterCommand = new RelayCommand(() => FilterConsoles());
|
||||||
|
}
|
||||||
|
|
||||||
|
public IAsyncRelayCommand LoadData { get; }
|
||||||
|
public ICommand GoBackCommand { get; }
|
||||||
|
public IAsyncRelayCommand SelectMachineCommand { get; }
|
||||||
|
public ICommand ComputersFilterCommand { get; }
|
||||||
|
public ICommand ConsolesFilterCommand { get; }
|
||||||
|
|
||||||
|
public string Title { get; } = "GPU Details";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Loads GPU details including resolutions, computers, and consoles
|
||||||
|
/// </summary>
|
||||||
|
private async Task LoadDataAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
IsLoading = true;
|
||||||
|
ErrorMessage = string.Empty;
|
||||||
|
HasError = false;
|
||||||
|
IsDataLoaded = false;
|
||||||
|
Resolutions.Clear();
|
||||||
|
Computers.Clear();
|
||||||
|
Consoles.Clear();
|
||||||
|
|
||||||
|
if(GpuId <= 0)
|
||||||
|
{
|
||||||
|
ErrorMessage = _localizer["Invalid GPU ID"].Value;
|
||||||
|
HasError = true;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogInformation("Loading GPU details for ID: {GpuId}", GpuId);
|
||||||
|
|
||||||
|
// Load GPU details
|
||||||
|
Gpu = await _gpusService.GetGpuByIdAsync(GpuId);
|
||||||
|
|
||||||
|
if(Gpu is null)
|
||||||
|
{
|
||||||
|
ErrorMessage = _localizer["Graphics processing unit not found"].Value;
|
||||||
|
HasError = true;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set manufacturer name (from Company field or fetch by CompanyId if empty)
|
||||||
|
ManufacturerName = Gpu.Company ?? string.Empty;
|
||||||
|
|
||||||
|
if(string.IsNullOrEmpty(ManufacturerName) && Gpu.CompanyId.HasValue)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
CompanyDto? company = await _companiesService.GetCompanyByIdAsync(Gpu.CompanyId.Value);
|
||||||
|
if(company != null) ManufacturerName = company.Name ?? string.Empty;
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogWarning(ex, "Failed to load company for GPU {GpuId}", GpuId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format display name
|
||||||
|
string displayName = Gpu.Name ?? string.Empty;
|
||||||
|
|
||||||
|
if(displayName == "DB_FRAMEBUFFER")
|
||||||
|
displayName = "Framebuffer";
|
||||||
|
else if(displayName == "DB_SOFTWARE")
|
||||||
|
displayName = "Software";
|
||||||
|
else if(displayName == "DB_NONE") displayName = "None";
|
||||||
|
|
||||||
|
_logger.LogInformation("GPU loaded: {Name}, Company: {Company}", displayName, ManufacturerName);
|
||||||
|
|
||||||
|
// Load resolutions
|
||||||
|
try
|
||||||
|
{
|
||||||
|
List<ResolutionByGpuDto>? resolutions = await _gpusService.GetResolutionsByGpuAsync(GpuId);
|
||||||
|
|
||||||
|
if(resolutions != null && resolutions.Count > 0)
|
||||||
|
{
|
||||||
|
Resolutions.Clear();
|
||||||
|
|
||||||
|
foreach(ResolutionByGpuDto res in resolutions)
|
||||||
|
{
|
||||||
|
// Get the full resolution DTO using the resolution ID
|
||||||
|
if(res.ResolutionId.HasValue)
|
||||||
|
{
|
||||||
|
ResolutionDto? resolutionDto =
|
||||||
|
await _gpusService.GetResolutionByIdAsync(res.ResolutionId.Value);
|
||||||
|
|
||||||
|
if(resolutionDto != null)
|
||||||
|
{
|
||||||
|
Resolutions.Add(new ResolutionItem
|
||||||
|
{
|
||||||
|
Id = resolutionDto.Id ?? 0,
|
||||||
|
Name = $"{resolutionDto.Width}x{resolutionDto.Height}",
|
||||||
|
Width = resolutionDto.Width ?? 0,
|
||||||
|
Height = resolutionDto.Height ?? 0,
|
||||||
|
Colors = resolutionDto.Colors ?? 0,
|
||||||
|
Palette = resolutionDto.Palette ?? 0,
|
||||||
|
Chars = resolutionDto.Chars ?? false,
|
||||||
|
Grayscale = resolutionDto.Grayscale ?? false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogInformation("Loaded {Count} resolutions for GPU {GpuId}", Resolutions.Count, GpuId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogWarning(ex, "Failed to load resolutions for GPU {GpuId}", GpuId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load machines and separate into computers and consoles
|
||||||
|
try
|
||||||
|
{
|
||||||
|
List<MachineDto>? machines = await _gpusService.GetMachinesByGpuAsync(GpuId);
|
||||||
|
|
||||||
|
if(machines != null && machines.Count > 0)
|
||||||
|
{
|
||||||
|
Computers.Clear();
|
||||||
|
Consoles.Clear();
|
||||||
|
|
||||||
|
foreach(MachineDto machine in machines)
|
||||||
|
{
|
||||||
|
var machineItem = new MachineItem
|
||||||
|
{
|
||||||
|
Id = machine.Id ?? 0,
|
||||||
|
Name = machine.Name ?? string.Empty,
|
||||||
|
Manufacturer = machine.Company ?? string.Empty,
|
||||||
|
Year = machine.Introduced?.Year ?? 0
|
||||||
|
};
|
||||||
|
|
||||||
|
// Distinguish between computers and consoles based on Type
|
||||||
|
if(machine.Type == 2) // MachineType.Console
|
||||||
|
Consoles.Add(machineItem);
|
||||||
|
else // MachineType.Computer or Unknown
|
||||||
|
Computers.Add(machineItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
HasComputers = Computers.Count > 0;
|
||||||
|
HasConsoles = Consoles.Count > 0;
|
||||||
|
|
||||||
|
// Initialize filtered collections
|
||||||
|
FilterComputers();
|
||||||
|
FilterConsoles();
|
||||||
|
|
||||||
|
_logger.LogInformation("Loaded {ComputerCount} computers and {ConsoleCount} consoles for GPU {GpuId}",
|
||||||
|
Computers.Count,
|
||||||
|
Consoles.Count,
|
||||||
|
GpuId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
HasComputers = false;
|
||||||
|
HasConsoles = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogWarning(ex, "Failed to load machines for GPU {GpuId}", GpuId);
|
||||||
|
HasComputers = false;
|
||||||
|
HasConsoles = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
IsDataLoaded = true;
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Error loading GPU details: {Exception}", ex.Message);
|
||||||
|
ErrorMessage = _localizer["Failed to load graphics processing unit details. Please try again later."].Value;
|
||||||
|
HasError = true;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
IsLoading = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Filters computers based on search text
|
||||||
|
/// </summary>
|
||||||
|
private void FilterComputers()
|
||||||
|
{
|
||||||
|
if(string.IsNullOrWhiteSpace(ComputersFilterText))
|
||||||
|
{
|
||||||
|
FilteredComputers.Clear();
|
||||||
|
foreach(MachineItem computer in Computers) FilteredComputers.Add(computer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var filtered = Computers
|
||||||
|
.Where(c => c.Name.Contains(ComputersFilterText, StringComparison.OrdinalIgnoreCase))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
FilteredComputers.Clear();
|
||||||
|
foreach(MachineItem computer in filtered) FilteredComputers.Add(computer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Filters consoles based on search text
|
||||||
|
/// </summary>
|
||||||
|
private void FilterConsoles()
|
||||||
|
{
|
||||||
|
if(string.IsNullOrWhiteSpace(ConsoelsFilterText))
|
||||||
|
{
|
||||||
|
FilteredConsoles.Clear();
|
||||||
|
foreach(MachineItem console in Consoles) FilteredConsoles.Add(console);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var filtered = Consoles.Where(c => c.Name.Contains(ConsoelsFilterText, StringComparison.OrdinalIgnoreCase))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
FilteredConsoles.Clear();
|
||||||
|
foreach(MachineItem console in filtered) FilteredConsoles.Add(console);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Navigates back to the GPU list
|
||||||
|
/// </summary>
|
||||||
|
private async Task GoBackAsync()
|
||||||
|
{
|
||||||
|
// If we came from a machine view, go back to machine view
|
||||||
|
if(_navigationSource is MachineViewViewModel machineVm)
|
||||||
|
{
|
||||||
|
await _navigator.NavigateViewModelAsync<MachineViewViewModel>(this);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default: go back to GPU list
|
||||||
|
await _navigator.NavigateViewModelAsync<GpusListViewModel>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Navigates to machine detail view
|
||||||
|
/// </summary>
|
||||||
|
private async Task SelectMachineAsync(int machineId)
|
||||||
|
{
|
||||||
|
if(machineId <= 0) return;
|
||||||
|
|
||||||
|
var navParam = new MachineViewNavigationParameter
|
||||||
|
{
|
||||||
|
MachineId = machineId
|
||||||
|
};
|
||||||
|
|
||||||
|
await _navigator.NavigateViewModelAsync<MachineViewViewModel>(this, data: navParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the navigation source (where we came from).
|
||||||
|
/// </summary>
|
||||||
|
public void SetNavigationSource(object? source)
|
||||||
|
{
|
||||||
|
_navigationSource = source;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Resolution item for displaying GPU supported resolutions
|
||||||
|
/// </summary>
|
||||||
|
public class ResolutionItem
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
public int Width { get; set; }
|
||||||
|
public int Height { get; set; }
|
||||||
|
public long Colors { get; set; }
|
||||||
|
public long Palette { get; set; }
|
||||||
|
public bool Chars { get; set; }
|
||||||
|
public bool Grayscale { get; set; }
|
||||||
|
|
||||||
|
public string Resolution => $"{Width}x{Height}";
|
||||||
|
|
||||||
|
public string ResolutionType => Chars ? "Text" : "Pixel";
|
||||||
|
|
||||||
|
public string ResolutionDisplay => Chars ? $"{Width}x{Height} characters" : $"{Width}x{Height}";
|
||||||
|
|
||||||
|
public string ColorDisplay => Grayscale
|
||||||
|
? $"{Colors} grays"
|
||||||
|
: Palette > 0
|
||||||
|
? $"{Colors} colors from a palette of {Palette} colors"
|
||||||
|
: $"{Colors} colors";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Machine item for displaying computers or consoles that use the GPU
|
||||||
|
/// </summary>
|
||||||
|
public class MachineItem
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
public string Manufacturer { get; set; } = string.Empty;
|
||||||
|
public int Year { get; set; }
|
||||||
|
|
||||||
|
public string YearDisplay => Year > 0 ? Year.ToString() : "Unknown";
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Marechai.App.Presentation.Models;
|
||||||
using Marechai.App.Services;
|
using Marechai.App.Services;
|
||||||
using Uno.Extensions.Navigation;
|
using Uno.Extensions.Navigation;
|
||||||
|
|
||||||
@@ -187,8 +188,14 @@ public partial class GpusListViewModel : ObservableObject
|
|||||||
|
|
||||||
_logger.LogInformation("Navigating to GPU detail: {GpuName} (ID: {GpuId})", gpu.Name, gpu.Id);
|
_logger.LogInformation("Navigating to GPU detail: {GpuName} (ID: {GpuId})", gpu.Name, gpu.Id);
|
||||||
|
|
||||||
// For now, we'll just log it. Implement detail page navigation when ready.
|
// Navigate to GPU detail view with navigation parameter
|
||||||
// await _navigator.NavigateViewModelAsync<GpuDetailViewModel>(this, data: gpu);
|
var navParam = new GpuDetailNavigationParameter
|
||||||
|
{
|
||||||
|
GpuId = gpu.Id,
|
||||||
|
NavigationSource = this
|
||||||
|
};
|
||||||
|
|
||||||
|
await _navigator.NavigateViewModelAsync<GpuDetailViewModel>(this, data: navParam);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -167,6 +167,20 @@ public partial class MachineViewViewModel : ObservableObject
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we came from GpuDetailViewModel, navigate back to GPU details
|
||||||
|
if(_navigationSource is GpuDetailViewModel gpuDetailVm)
|
||||||
|
{
|
||||||
|
var navParam = new GpuDetailNavigationParameter
|
||||||
|
{
|
||||||
|
GpuId = gpuDetailVm.GpuId,
|
||||||
|
NavigationSource = this
|
||||||
|
};
|
||||||
|
|
||||||
|
await _navigator.NavigateViewModelAsync<GpuDetailViewModel>(this, data: navParam);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Otherwise, try to go back in the navigation stack
|
// Otherwise, try to go back in the navigation stack
|
||||||
await _navigator.GoBack(this);
|
await _navigator.GoBack(this);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ public partial class MainViewModel : ObservableObject
|
|||||||
NavigateToConsolesCommand = new AsyncRelayCommand(() => NavigateTo("consoles"));
|
NavigateToConsolesCommand = new AsyncRelayCommand(() => NavigateTo("consoles"));
|
||||||
NavigateToDocumentsCommand = new AsyncRelayCommand(() => NavigateTo("documents"));
|
NavigateToDocumentsCommand = new AsyncRelayCommand(() => NavigateTo("documents"));
|
||||||
NavigateToDumpsCommand = new AsyncRelayCommand(() => NavigateTo("dumps"));
|
NavigateToDumpsCommand = new AsyncRelayCommand(() => NavigateTo("dumps"));
|
||||||
NavigateToGraphicalProcessingUnitsCommand = new AsyncRelayCommand(() => NavigateTo("gpus/list-gpus"));
|
NavigateToGraphicalProcessingUnitsCommand = new AsyncRelayCommand(() => NavigateTo("gpus"));
|
||||||
NavigateToMagazinesCommand = new AsyncRelayCommand(() => NavigateTo("magazines"));
|
NavigateToMagazinesCommand = new AsyncRelayCommand(() => NavigateTo("magazines"));
|
||||||
NavigateToPeopleCommand = new AsyncRelayCommand(() => NavigateTo("people"));
|
NavigateToPeopleCommand = new AsyncRelayCommand(() => NavigateTo("people"));
|
||||||
NavigateToProcessorsCommand = new AsyncRelayCommand(() => NavigateTo("processors"));
|
NavigateToProcessorsCommand = new AsyncRelayCommand(() => NavigateTo("processors"));
|
||||||
|
|||||||
383
Marechai.App/Presentation/Views/GpuDetailPage.xaml
Normal file
383
Marechai.App/Presentation/Views/GpuDetailPage.xaml
Normal file
@@ -0,0 +1,383 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Page x:Class="Marechai.App.Presentation.Views.GpuDetailPage"
|
||||||
|
x:Name="PageRoot"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:utu="using:Uno.Toolkit.UI"
|
||||||
|
xmlns:controls="using:CommunityToolkit.WinUI.UI.Controls"
|
||||||
|
NavigationCacheMode="Required"
|
||||||
|
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||||
|
|
||||||
|
<Page.Resources>
|
||||||
|
</Page.Resources>
|
||||||
|
|
||||||
|
<Grid utu:SafeArea.Insets="VisibleBounds">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<!-- Header with Back Button -->
|
||||||
|
<Grid Grid.Row="0"
|
||||||
|
Padding="8"
|
||||||
|
Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<AppBarButton Grid.Column="0"
|
||||||
|
Icon="Back"
|
||||||
|
Label="Back"
|
||||||
|
Command="{Binding GoBackCommand}"
|
||||||
|
AutomationProperties.Name="Go back" />
|
||||||
|
<TextBlock Grid.Column="1"
|
||||||
|
Text="GPU Details"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
FontSize="18"
|
||||||
|
FontWeight="SemiBold" />
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<!-- Content -->
|
||||||
|
<ScrollViewer Grid.Row="1">
|
||||||
|
<StackPanel Padding="16"
|
||||||
|
Spacing="16">
|
||||||
|
|
||||||
|
<!-- Loading State -->
|
||||||
|
<StackPanel Visibility="{Binding IsLoading}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
Padding="32"
|
||||||
|
Spacing="16">
|
||||||
|
<ProgressRing IsActive="True"
|
||||||
|
IsIndeterminate="True"
|
||||||
|
Height="48"
|
||||||
|
Width="48" />
|
||||||
|
<TextBlock Text="Loading..."
|
||||||
|
TextAlignment="Center"
|
||||||
|
FontSize="14" />
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Error State -->
|
||||||
|
<StackPanel Visibility="{Binding HasError}"
|
||||||
|
Padding="16"
|
||||||
|
Background="{ThemeResource SystemErrorBackgroundColor}"
|
||||||
|
CornerRadius="8"
|
||||||
|
Spacing="8">
|
||||||
|
<TextBlock Text="Error"
|
||||||
|
FontWeight="Bold"
|
||||||
|
Foreground="{ThemeResource SystemErrorTextForegroundColor}" />
|
||||||
|
<TextBlock Text="{Binding ErrorMessage}"
|
||||||
|
Foreground="{ThemeResource SystemErrorTextForegroundColor}"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- GPU Details -->
|
||||||
|
<StackPanel Visibility="{Binding IsDataLoaded}"
|
||||||
|
Spacing="16">
|
||||||
|
|
||||||
|
<!-- GPU Name -->
|
||||||
|
<TextBlock Text="{Binding Gpu.Name}"
|
||||||
|
FontSize="28"
|
||||||
|
FontWeight="Bold"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
|
|
||||||
|
<!-- Company/Manufacturer -->
|
||||||
|
<StackPanel Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||||
|
CornerRadius="8"
|
||||||
|
Padding="12"
|
||||||
|
Spacing="8">
|
||||||
|
<TextBlock Text="Manufacturer"
|
||||||
|
FontSize="14"
|
||||||
|
FontWeight="SemiBold"
|
||||||
|
Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding ManufacturerName}"
|
||||||
|
FontSize="14"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Model Code -->
|
||||||
|
<StackPanel Visibility="{Binding Gpu.ModelCode, Converter={StaticResource StringToVisibilityConverter}}"
|
||||||
|
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||||
|
CornerRadius="8"
|
||||||
|
Padding="12"
|
||||||
|
Spacing="8">
|
||||||
|
<TextBlock Text="Model Code"
|
||||||
|
FontSize="14"
|
||||||
|
FontWeight="SemiBold"
|
||||||
|
Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding Gpu.ModelCode}"
|
||||||
|
FontSize="14"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Introduced Date -->
|
||||||
|
<StackPanel Visibility="{Binding Gpu.Introduced, Converter={StaticResource ObjectToVisibilityConverter}}"
|
||||||
|
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||||
|
CornerRadius="8"
|
||||||
|
Padding="12"
|
||||||
|
Spacing="8">
|
||||||
|
<TextBlock Text="Introduced"
|
||||||
|
FontSize="14"
|
||||||
|
FontWeight="SemiBold"
|
||||||
|
Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding Gpu.Introduced}"
|
||||||
|
FontSize="14" />
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Package -->
|
||||||
|
<StackPanel Visibility="{Binding Gpu.Package, Converter={StaticResource StringToVisibilityConverter}}"
|
||||||
|
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||||
|
CornerRadius="8"
|
||||||
|
Padding="12"
|
||||||
|
Spacing="8">
|
||||||
|
<TextBlock Text="Package"
|
||||||
|
FontSize="14"
|
||||||
|
FontWeight="SemiBold"
|
||||||
|
Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding Gpu.Package}"
|
||||||
|
FontSize="14"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Process -->
|
||||||
|
<StackPanel Visibility="{Binding Gpu.Process, Converter={StaticResource StringToVisibilityConverter}}"
|
||||||
|
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||||
|
CornerRadius="8"
|
||||||
|
Padding="12"
|
||||||
|
Spacing="8">
|
||||||
|
<TextBlock Text="Process"
|
||||||
|
FontSize="14"
|
||||||
|
FontWeight="SemiBold"
|
||||||
|
Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding Gpu.Process}"
|
||||||
|
FontSize="14"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Process (nm) -->
|
||||||
|
<StackPanel Visibility="{Binding Gpu.ProcessNm, Converter={StaticResource StringToVisibilityConverter}}"
|
||||||
|
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||||
|
CornerRadius="8"
|
||||||
|
Padding="12"
|
||||||
|
Spacing="8">
|
||||||
|
<TextBlock Text="Process (nm)"
|
||||||
|
FontSize="14"
|
||||||
|
FontWeight="SemiBold"
|
||||||
|
Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding Gpu.ProcessNm}"
|
||||||
|
FontSize="14"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Die Size -->
|
||||||
|
<StackPanel Visibility="{Binding Gpu.DieSize, Converter={StaticResource ObjectToVisibilityConverter}}"
|
||||||
|
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||||
|
CornerRadius="8"
|
||||||
|
Padding="12"
|
||||||
|
Spacing="8">
|
||||||
|
<TextBlock Text="Die Size (mm²)"
|
||||||
|
FontSize="14"
|
||||||
|
FontWeight="SemiBold"
|
||||||
|
Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding Gpu.DieSize}"
|
||||||
|
FontSize="14"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Transistors -->
|
||||||
|
<StackPanel Visibility="{Binding Gpu.Transistors, Converter={StaticResource ObjectToVisibilityConverter}}"
|
||||||
|
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||||
|
CornerRadius="8"
|
||||||
|
Padding="12"
|
||||||
|
Spacing="8">
|
||||||
|
<TextBlock Text="Transistors"
|
||||||
|
FontSize="14"
|
||||||
|
FontWeight="SemiBold"
|
||||||
|
Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding Gpu.Transistors}"
|
||||||
|
FontSize="14"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Resolutions Section -->
|
||||||
|
<StackPanel Visibility="{Binding Resolutions.Count, Converter={StaticResource ZeroToVisibilityConverter}}"
|
||||||
|
Spacing="8">
|
||||||
|
<StackPanel Orientation="Horizontal"
|
||||||
|
Spacing="8">
|
||||||
|
<TextBlock Text="Supported Resolutions"
|
||||||
|
FontSize="14"
|
||||||
|
FontWeight="SemiBold"
|
||||||
|
Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding Resolutions.Count}"
|
||||||
|
FontSize="14"
|
||||||
|
FontWeight="Bold"
|
||||||
|
Foreground="{ThemeResource SystemAccentColor}" />
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Scrollable Resolutions List -->
|
||||||
|
<ScrollViewer Height="200"
|
||||||
|
BorderThickness="1"
|
||||||
|
BorderBrush="{ThemeResource ControlElevationBorderBrush}"
|
||||||
|
CornerRadius="8">
|
||||||
|
<ItemsRepeater ItemsSource="{Binding Resolutions}"
|
||||||
|
Margin="0">
|
||||||
|
<ItemsRepeater.Layout>
|
||||||
|
<StackLayout Spacing="4" />
|
||||||
|
</ItemsRepeater.Layout>
|
||||||
|
<ItemsRepeater.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<Border Padding="12,8"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||||
|
CornerRadius="4"
|
||||||
|
Margin="0,4">
|
||||||
|
<StackPanel Spacing="4">
|
||||||
|
<!-- First line: Resolution dimensions or format -->
|
||||||
|
<TextBlock Text="{Binding ResolutionDisplay}"
|
||||||
|
FontSize="14"
|
||||||
|
FontWeight="SemiBold" />
|
||||||
|
<!-- Second line: Color/palette information -->
|
||||||
|
<TextBlock Text="{Binding ColorDisplay}"
|
||||||
|
FontSize="12"
|
||||||
|
Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
</DataTemplate>
|
||||||
|
</ItemsRepeater.ItemTemplate>
|
||||||
|
</ItemsRepeater>
|
||||||
|
</ScrollViewer>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Computers Section -->
|
||||||
|
<StackPanel Visibility="{Binding HasComputers}"
|
||||||
|
Spacing="8">
|
||||||
|
<StackPanel Orientation="Horizontal"
|
||||||
|
Spacing="8">
|
||||||
|
<TextBlock Text="Computers"
|
||||||
|
FontSize="14"
|
||||||
|
FontWeight="SemiBold"
|
||||||
|
Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding Computers.Count}"
|
||||||
|
FontSize="14"
|
||||||
|
FontWeight="Bold"
|
||||||
|
Foreground="{ThemeResource SystemAccentColor}" />
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Filter Box -->
|
||||||
|
<AutoSuggestBox PlaceholderText="Filter computers..."
|
||||||
|
Text="{Binding ComputersFilterText, Mode=TwoWay}"
|
||||||
|
TextChanged="ComputersSearchBox_TextChanged"
|
||||||
|
BorderThickness="1"
|
||||||
|
BorderBrush="{ThemeResource ControlElevationBorderBrush}" />
|
||||||
|
|
||||||
|
<!-- Scrollable Computers List -->
|
||||||
|
<ScrollViewer Height="200"
|
||||||
|
BorderThickness="1"
|
||||||
|
BorderBrush="{ThemeResource ControlElevationBorderBrush}"
|
||||||
|
CornerRadius="8">
|
||||||
|
<ItemsRepeater ItemsSource="{Binding FilteredComputers}"
|
||||||
|
Margin="0">
|
||||||
|
<ItemsRepeater.Layout>
|
||||||
|
<StackLayout Spacing="4" />
|
||||||
|
</ItemsRepeater.Layout>
|
||||||
|
<ItemsRepeater.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<Button Click="Computer_Click"
|
||||||
|
Tag="{Binding Id}"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
HorizontalContentAlignment="Left"
|
||||||
|
Padding="12"
|
||||||
|
Margin="0,4">
|
||||||
|
<StackPanel Spacing="4"
|
||||||
|
HorizontalAlignment="Left">
|
||||||
|
<TextBlock Text="{Binding Name}"
|
||||||
|
FontSize="14"
|
||||||
|
FontWeight="SemiBold" />
|
||||||
|
<StackPanel Orientation="Horizontal"
|
||||||
|
Spacing="8">
|
||||||
|
<TextBlock Text="{Binding Manufacturer}"
|
||||||
|
FontSize="12"
|
||||||
|
Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding YearDisplay}"
|
||||||
|
FontSize="12"
|
||||||
|
Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
</DataTemplate>
|
||||||
|
</ItemsRepeater.ItemTemplate>
|
||||||
|
</ItemsRepeater>
|
||||||
|
</ScrollViewer>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Consoles Section -->
|
||||||
|
<StackPanel Visibility="{Binding HasConsoles}"
|
||||||
|
Spacing="8">
|
||||||
|
<StackPanel Orientation="Horizontal"
|
||||||
|
Spacing="8">
|
||||||
|
<TextBlock Text="Consoles"
|
||||||
|
FontSize="14"
|
||||||
|
FontWeight="SemiBold"
|
||||||
|
Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding Consoles.Count}"
|
||||||
|
FontSize="14"
|
||||||
|
FontWeight="Bold"
|
||||||
|
Foreground="{ThemeResource SystemAccentColor}" />
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Filter Box -->
|
||||||
|
<AutoSuggestBox PlaceholderText="Filter consoles..."
|
||||||
|
Text="{Binding ConsoelsFilterText, Mode=TwoWay}"
|
||||||
|
TextChanged="ConsolesSearchBox_TextChanged"
|
||||||
|
BorderThickness="1"
|
||||||
|
BorderBrush="{ThemeResource ControlElevationBorderBrush}" />
|
||||||
|
|
||||||
|
<!-- Scrollable Consoles List -->
|
||||||
|
<ScrollViewer Height="200"
|
||||||
|
BorderThickness="1"
|
||||||
|
BorderBrush="{ThemeResource ControlElevationBorderBrush}"
|
||||||
|
CornerRadius="8">
|
||||||
|
<ItemsRepeater ItemsSource="{Binding FilteredConsoles}"
|
||||||
|
Margin="0">
|
||||||
|
<ItemsRepeater.Layout>
|
||||||
|
<StackLayout Spacing="4" />
|
||||||
|
</ItemsRepeater.Layout>
|
||||||
|
<ItemsRepeater.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<Button Click="Console_Click"
|
||||||
|
Tag="{Binding Id}"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
HorizontalContentAlignment="Left"
|
||||||
|
Padding="12"
|
||||||
|
Margin="0,4">
|
||||||
|
<StackPanel Spacing="4"
|
||||||
|
HorizontalAlignment="Left">
|
||||||
|
<TextBlock Text="{Binding Name}"
|
||||||
|
FontSize="14"
|
||||||
|
FontWeight="SemiBold" />
|
||||||
|
<StackPanel Orientation="Horizontal"
|
||||||
|
Spacing="8">
|
||||||
|
<TextBlock Text="{Binding Manufacturer}"
|
||||||
|
FontSize="12"
|
||||||
|
Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
<TextBlock Text="{Binding YearDisplay}"
|
||||||
|
FontSize="12"
|
||||||
|
Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
</DataTemplate>
|
||||||
|
</ItemsRepeater.ItemTemplate>
|
||||||
|
</ItemsRepeater>
|
||||||
|
</ScrollViewer>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
</StackPanel>
|
||||||
|
</ScrollViewer>
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
</Page>
|
||||||
98
Marechai.App/Presentation/Views/GpuDetailPage.xaml.cs
Normal file
98
Marechai.App/Presentation/Views/GpuDetailPage.xaml.cs
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
#nullable enable
|
||||||
|
|
||||||
|
using Marechai.App.Presentation.Models;
|
||||||
|
using Marechai.App.Presentation.ViewModels;
|
||||||
|
using Microsoft.UI.Xaml;
|
||||||
|
using Microsoft.UI.Xaml.Controls;
|
||||||
|
using Microsoft.UI.Xaml.Navigation;
|
||||||
|
|
||||||
|
namespace Marechai.App.Presentation.Views;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// GPU detail page showing all information, resolutions, computers, and consoles
|
||||||
|
/// </summary>
|
||||||
|
public sealed partial class GpuDetailPage : Page
|
||||||
|
{
|
||||||
|
private object? _navigationSource;
|
||||||
|
private int? _pendingGpuId;
|
||||||
|
|
||||||
|
public GpuDetailPage()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
DataContextChanged += GpuDetailPage_DataContextChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||||
|
{
|
||||||
|
base.OnNavigatedTo(e);
|
||||||
|
|
||||||
|
int? gpuId = null;
|
||||||
|
|
||||||
|
// Handle both int and GpuDetailNavigationParameter
|
||||||
|
if(e.Parameter is int intId)
|
||||||
|
gpuId = intId;
|
||||||
|
else if(e.Parameter is GpuDetailNavigationParameter navParam)
|
||||||
|
{
|
||||||
|
gpuId = navParam.GpuId;
|
||||||
|
_navigationSource = navParam.NavigationSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(gpuId.HasValue)
|
||||||
|
{
|
||||||
|
_pendingGpuId = gpuId;
|
||||||
|
|
||||||
|
if(DataContext is GpuDetailViewModel viewModel)
|
||||||
|
{
|
||||||
|
viewModel.GpuId = gpuId.Value;
|
||||||
|
if(_navigationSource != null) viewModel.SetNavigationSource(_navigationSource);
|
||||||
|
_ = viewModel.LoadData.ExecuteAsync(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GpuDetailPage_DataContextChanged(FrameworkElement sender, DataContextChangedEventArgs args)
|
||||||
|
{
|
||||||
|
if(DataContext is GpuDetailViewModel viewModel && _pendingGpuId.HasValue)
|
||||||
|
{
|
||||||
|
viewModel.GpuId = _pendingGpuId.Value;
|
||||||
|
if(_navigationSource != null) viewModel.SetNavigationSource(_navigationSource);
|
||||||
|
_ = viewModel.LoadData.ExecuteAsync(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ComputersSearchBox_QuerySubmitted(AutoSuggestBox sender, AutoSuggestBoxQuerySubmittedEventArgs args)
|
||||||
|
{
|
||||||
|
if(DataContext is GpuDetailViewModel vm) vm.ComputersFilterCommand.Execute(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ComputersSearchBox_TextChanged(AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args)
|
||||||
|
{
|
||||||
|
if(args.Reason == AutoSuggestionBoxTextChangeReason.UserInput)
|
||||||
|
if(DataContext is GpuDetailViewModel vm)
|
||||||
|
vm.ComputersFilterCommand.Execute(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ConsolesSearchBox_QuerySubmitted(AutoSuggestBox sender, AutoSuggestBoxQuerySubmittedEventArgs args)
|
||||||
|
{
|
||||||
|
if(DataContext is GpuDetailViewModel vm) vm.ConsolesFilterCommand.Execute(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ConsolesSearchBox_TextChanged(AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args)
|
||||||
|
{
|
||||||
|
if(args.Reason == AutoSuggestionBoxTextChangeReason.UserInput)
|
||||||
|
if(DataContext is GpuDetailViewModel vm)
|
||||||
|
vm.ConsolesFilterCommand.Execute(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Computer_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if(sender is Button button && button.Tag is int machineId && DataContext is GpuDetailViewModel vm)
|
||||||
|
_ = vm.SelectMachineCommand.ExecuteAsync(machineId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Console_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if(sender is Button button && button.Tag is int machineId && DataContext is GpuDetailViewModel vm)
|
||||||
|
_ = vm.SelectMachineCommand.ExecuteAsync(machineId);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -72,4 +72,91 @@ public class GpusService
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fetches resolutions supported by a GPU
|
||||||
|
/// </summary>
|
||||||
|
public async Task<List<ResolutionByGpuDto>> GetResolutionsByGpuAsync(int gpuId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_logger.LogInformation("Fetching resolutions for GPU {GpuId}", gpuId);
|
||||||
|
|
||||||
|
// Fetch from the resolutions-by-gpu/gpus/{gpuId}/resolutions endpoint
|
||||||
|
List<ResolutionByGpuDto> resolutions = await _apiClient.ResolutionsByGpu.Gpus[gpuId].Resolutions.GetAsync();
|
||||||
|
|
||||||
|
if(resolutions == null) return [];
|
||||||
|
|
||||||
|
_logger.LogInformation("Successfully fetched {Count} resolutions for GPU {GpuId}",
|
||||||
|
resolutions.Count,
|
||||||
|
gpuId);
|
||||||
|
|
||||||
|
return resolutions;
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogWarning(ex, "Error fetching resolutions for GPU {GpuId}", gpuId);
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fetches machines that use a specific GPU
|
||||||
|
/// </summary>
|
||||||
|
public async Task<List<MachineDto>> GetMachinesByGpuAsync(int gpuId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_logger.LogInformation("Fetching machines for GPU {GpuId}", gpuId);
|
||||||
|
|
||||||
|
// Fetch from the gpus/{gpuId}/machines endpoint
|
||||||
|
List<MachineDto> machines = await _apiClient.Gpus[gpuId].Machines.GetAsync();
|
||||||
|
|
||||||
|
if(machines == null) return [];
|
||||||
|
|
||||||
|
_logger.LogInformation("Successfully fetched {Count} machines for GPU {GpuId}", machines.Count, gpuId);
|
||||||
|
|
||||||
|
return machines;
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogWarning(ex, "Error fetching machines for GPU {GpuId}", gpuId);
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fetches a single resolution by ID from the API
|
||||||
|
/// </summary>
|
||||||
|
public async Task<ResolutionDto?> GetResolutionByIdAsync(int resolutionId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_logger.LogInformation("Fetching resolution {ResolutionId} from API", resolutionId);
|
||||||
|
|
||||||
|
ResolutionDto? resolution = await _apiClient.Resolutions[resolutionId].GetAsync();
|
||||||
|
|
||||||
|
if(resolution == null)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Resolution {ResolutionId} not found", resolutionId);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogInformation("Successfully fetched resolution {ResolutionId}: {Width}x{Height}",
|
||||||
|
resolutionId,
|
||||||
|
resolution.Width,
|
||||||
|
resolution.Height);
|
||||||
|
|
||||||
|
return resolution;
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogWarning(ex, "Error fetching resolution {ResolutionId} from API", resolutionId);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user