No need to use untypenode extraction anymore.

This commit is contained in:
2025-11-15 22:44:02 +00:00
parent 4f59f6870d
commit dbef655a3d
10 changed files with 45 additions and 125 deletions

View File

@@ -1,61 +0,0 @@
using Microsoft.Kiota.Abstractions.Serialization;
namespace Marechai.App.Helpers;
/// <summary>
/// Helper class for extracting values from Kiota UntypedNode objects.
/// </summary>
public static class UntypedNodeExtractor
{
/// <summary>
/// Extracts an integer value from an UntypedNode.
/// </summary>
/// <param name="node">The UntypedNode to extract from. Can be null.</param>
/// <returns>The extracted integer value, or 0 if extraction fails.</returns>
public static int ExtractInt(UntypedNode? node)
{
if(node == null) return 0;
try
{
// Cast to UntypedInteger to access the Value property
if(node is UntypedInteger intNode) return intNode.GetValue();
// Fallback: try to parse ToString() result
var stringValue = node.ToString();
if(!string.IsNullOrWhiteSpace(stringValue) && int.TryParse(stringValue, out int result)) return result;
return 0;
}
catch
{
return 0;
}
}
/// <summary>
/// Extracts a long value from an UntypedNode.
/// </summary>
/// <param name="node">The UntypedNode to extract from. Can be null.</param>
/// <returns>The extracted long value, or 0 if extraction fails.</returns>
public static long ExtractLong(UntypedNode? node)
{
if(node == null) return 0;
try
{
if(node is UntypedInteger intNode) return intNode.GetValue();
var stringValue = node.ToString();
if(!string.IsNullOrWhiteSpace(stringValue) && long.TryParse(stringValue, out long result)) return result;
return 0;
}
catch
{
return 0;
}
}
}

View File

@@ -40,10 +40,10 @@
</UnoFeatures> </UnoFeatures>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Marechai.Data\Marechai.Data.csproj"/> <ProjectReference Include="..\Marechai.Data\Marechai.Data.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Humanizer"/> <PackageReference Include="Humanizer" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Update="Presentation\Views\Shell.xaml.cs"> <Compile Update="Presentation\Views\Shell.xaml.cs">

View File

@@ -7,12 +7,11 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Input; using System.Windows.Input;
using Marechai.App.Helpers;
using Marechai.App.Presentation.Models; using Marechai.App.Presentation.Models;
using Marechai.App.Services; using Marechai.App.Services;
using Marechai.App.Services.Caching; using Marechai.App.Services.Caching;
using Uno.Extensions.Navigation;
using Microsoft.UI.Xaml.Media.Imaging; using Microsoft.UI.Xaml.Media.Imaging;
using Uno.Extensions.Navigation;
namespace Marechai.App.Presentation.ViewModels; namespace Marechai.App.Presentation.ViewModels;
@@ -20,9 +19,9 @@ public partial class CompaniesViewModel : ObservableObject
{ {
private readonly List<CompanyListItem> _allCompanies = []; private readonly List<CompanyListItem> _allCompanies = [];
private readonly CompaniesService _companiesService; private readonly CompaniesService _companiesService;
private readonly CompanyLogoCache _logoCache;
private readonly IStringLocalizer _localizer; private readonly IStringLocalizer _localizer;
private readonly ILogger<CompaniesViewModel> _logger; private readonly ILogger<CompaniesViewModel> _logger;
private readonly CompanyLogoCache _logoCache;
private readonly INavigator _navigator; private readonly INavigator _navigator;
[ObservableProperty] [ObservableProperty]
@@ -49,9 +48,8 @@ public partial class CompaniesViewModel : ObservableObject
[ObservableProperty] [ObservableProperty]
private string _searchQuery = string.Empty; private string _searchQuery = string.Empty;
public CompaniesViewModel(CompaniesService companiesService, CompanyLogoCache logoCache, public CompaniesViewModel(CompaniesService companiesService, CompanyLogoCache logoCache, IStringLocalizer localizer,
IStringLocalizer localizer, ILogger<CompaniesViewModel> logger, ILogger<CompaniesViewModel> logger, INavigator navigator)
INavigator navigator)
{ {
_companiesService = companiesService; _companiesService = companiesService;
_logoCache = logoCache; _logoCache = logoCache;
@@ -98,34 +96,36 @@ public partial class CompaniesViewModel : ObservableObject
// Build the full list in memory // Build the full list in memory
foreach(CompanyDto company in companies) foreach(CompanyDto company in companies)
{ {
// Extract id from UntypedNode // Extract id from company
int companyId = UntypedNodeExtractor.ExtractInt(company.Id); int companyId = company.Id ?? 0;
// Convert DateTimeOffset? to DateTime? // Convert DateTimeOffset? to DateTime?
DateTime? foundedDate = company.Founded?.DateTime; DateTime? foundedDate = company.Founded?.DateTime;
// Load logo if available // Load logo if available
SvgImageSource? logoSource = null; SvgImageSource? logoSource = null;
if(company.LastLogo.HasValue) if(company.LastLogo.HasValue)
{ {
try try
{ {
var logoStream = await _logoCache.GetLogoAsync(company.LastLogo.Value); Stream? logoStream = await _logoCache.GetLogoAsync(company.LastLogo.Value);
logoSource = new SvgImageSource(); logoSource = new SvgImageSource();
await logoSource.SetSourceAsync(logoStream.AsRandomAccessStream()); await logoSource.SetSourceAsync(logoStream.AsRandomAccessStream());
} }
catch(Exception ex) catch(Exception ex)
{ {
_logger.LogWarning("Failed to load logo for company {CompanyId}: {Exception}", _logger.LogWarning("Failed to load logo for company {CompanyId}: {Exception}",
companyId, ex.Message); companyId,
ex.Message);
} }
} }
_allCompanies.Add(new CompanyListItem _allCompanies.Add(new CompanyListItem
{ {
Id = companyId, Id = companyId,
Name = company.Name ?? string.Empty, Name = company.Name ?? string.Empty,
FoundationDate = foundedDate, FoundationDate = foundedDate,
LogoImageSource = logoSource LogoImageSource = logoSource
}); });
} }
@@ -210,10 +210,10 @@ public partial class CompaniesViewModel : ObservableObject
/// </summary> /// </summary>
public class CompanyListItem public class CompanyListItem
{ {
public int Id { get; set; } public int Id { get; set; }
public string Name { get; set; } = string.Empty; public string Name { get; set; } = string.Empty;
public DateTime? FoundationDate { get; set; } public DateTime? FoundationDate { get; set; }
public SvgImageSource? LogoImageSource { get; set; } public SvgImageSource? LogoImageSource { get; set; }
public string FoundationDateDisplay => public string FoundationDateDisplay =>
FoundationDate.HasValue ? FoundationDate.Value.ToString("MMMM d, yyyy") : string.Empty; FoundationDate.HasValue ? FoundationDate.Value.ToString("MMMM d, yyyy") : string.Empty;

View File

@@ -7,7 +7,6 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Input; using System.Windows.Input;
using Marechai.App.Helpers;
using Marechai.App.Presentation.Models; using Marechai.App.Presentation.Models;
using Marechai.App.Services; using Marechai.App.Services;
using Marechai.App.Services.Caching; using Marechai.App.Services.Caching;
@@ -139,7 +138,7 @@ public partial class CompanyDetailViewModel : ObservableObject
} }
partial void OnCompanyLogosChanged(ObservableCollection<CompanyLogoItem>? oldValue, partial void OnCompanyLogosChanged(ObservableCollection<CompanyLogoItem>? oldValue,
ObservableCollection<CompanyLogoItem> newValue) ObservableCollection<CompanyLogoItem> newValue)
{ {
// Notify that HasMultipleLogos has changed // Notify that HasMultipleLogos has changed
OnPropertyChanged(nameof(HasMultipleLogos)); OnPropertyChanged(nameof(HasMultipleLogos));
@@ -365,7 +364,7 @@ public partial class CompanyDetailViewModel : ObservableObject
{ {
try try
{ {
var countryCode = (short)UntypedNodeExtractor.ExtractInt(Company.CountryId); var countryCode = (short)(Company.CountryId ?? 0);
Stream? flagStream = await _flagCache.GetFlagAsync(countryCode); Stream? flagStream = await _flagCache.GetFlagAsync(countryCode);
var flagSource = new SvgImageSource(); var flagSource = new SvgImageSource();
@@ -386,7 +385,7 @@ public partial class CompanyDetailViewModel : ObservableObject
if(Company.SoldToId != null) if(Company.SoldToId != null)
{ {
int soldToId = UntypedNodeExtractor.ExtractInt(Company.SoldToId); int soldToId = Company.SoldToId ?? 0;
if(soldToId > 0) SoldToCompany = await _companyDetailService.GetSoldToCompanyAsync(soldToId); if(soldToId > 0) SoldToCompany = await _companyDetailService.GetSoldToCompanyAsync(soldToId);
} }
@@ -421,9 +420,7 @@ public partial class CompanyDetailViewModel : ObservableObject
var logosWithYears = logosList.Select(logo => new var logosWithYears = logosList.Select(logo => new
{ {
Logo = logo, Logo = logo,
Year = logo.Year != null logo.Year
? (int?)UntypedNodeExtractor.ExtractInt(logo.Year)
: null
}) })
.OrderBy(l => l.Year) .OrderBy(l => l.Year)
.ToList(); .ToList();
@@ -472,7 +469,7 @@ public partial class CompanyDetailViewModel : ObservableObject
foreach(MachineDto machine in machines) foreach(MachineDto machine in machines)
{ {
int machineId = UntypedNodeExtractor.ExtractInt(machine.Id); int machineId = machine.Id ?? 0;
var machineItem = new CompanyDetailMachine var machineItem = new CompanyDetailMachine
{ {

View File

@@ -6,7 +6,6 @@ using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Input; using System.Windows.Input;
using Marechai.App.Helpers;
using Marechai.App.Presentation.Models; using Marechai.App.Presentation.Models;
using Marechai.App.Services; using Marechai.App.Services;
using Uno.Extensions.Navigation; using Uno.Extensions.Navigation;
@@ -186,7 +185,7 @@ public partial class ComputersListViewModel : ObservableObject
foreach(MachineDto computer in computers.OrderBy(c => c.Name)) foreach(MachineDto computer in computers.OrderBy(c => c.Name))
{ {
int year = computer.Introduced?.Year ?? 0; int year = computer.Introduced?.Year ?? 0;
int id = UntypedNodeExtractor.ExtractInt(computer.Id); int id = computer.Id ?? 0;
_logger.LogInformation("Computer: {Name}, Introduced: {Introduced}, Year: {Year}, Company: {Company}, ID: {Id}", _logger.LogInformation("Computer: {Name}, Introduced: {Introduced}, Year: {Year}, Company: {Company}, ID: {Id}",
computer.Name, computer.Name,

View File

@@ -6,7 +6,6 @@ using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Input; using System.Windows.Input;
using Marechai.App.Helpers;
using Marechai.App.Presentation.Models; using Marechai.App.Presentation.Models;
using Marechai.App.Services; using Marechai.App.Services;
using Uno.Extensions.Navigation; using Uno.Extensions.Navigation;
@@ -184,7 +183,7 @@ public partial class ConsolesListViewModel : ObservableObject
foreach(MachineDto console in consoles.OrderBy(c => c.Name)) foreach(MachineDto console in consoles.OrderBy(c => c.Name))
{ {
int year = console.Introduced?.Year ?? 0; int year = console.Introduced?.Year ?? 0;
int id = UntypedNodeExtractor.ExtractInt(console.Id); int id = console.Id ?? 0;
_logger.LogInformation("Console: {Name}, Introduced: {Introduced}, Year: {Year}, Company: {Company}, ID: {Id}", _logger.LogInformation("Console: {Name}, Introduced: {Introduced}, Year: {Year}, Company: {Company}, ID: {Id}",
console.Name, console.Name,

View File

@@ -32,7 +32,6 @@ using System.IO;
using System.Threading.Tasks; using System.Threading.Tasks;
using Windows.Storage.Streams; using Windows.Storage.Streams;
using Humanizer; using Humanizer;
using Marechai.App.Helpers;
using Marechai.App.Presentation.Models; using Marechai.App.Presentation.Models;
using Marechai.App.Services; using Marechai.App.Services;
using Marechai.App.Services.Caching; using Marechai.App.Services.Caching;
@@ -238,9 +237,9 @@ public partial class MachineViewViewModel : ObservableObject
foreach(ProcessorDto processor in machine.Processors) foreach(ProcessorDto processor in machine.Processors)
{ {
var details = new List<string>(); var details = new List<string>();
int speed = UntypedNodeExtractor.ExtractInt(processor.Speed); var speed = (int)(processor.Speed ?? 0);
int gprSize = UntypedNodeExtractor.ExtractInt(processor.GprSize); int gprSize = processor.GprSize ?? 0;
int cores = UntypedNodeExtractor.ExtractInt(processor.Cores); int cores = processor.Cores ?? 0;
if(speed > 0) details.Add($"{speed} MHz"); if(speed > 0) details.Add($"{speed} MHz");
if(gprSize > 0) details.Add($"{gprSize} bits"); if(gprSize > 0) details.Add($"{gprSize} bits");
@@ -261,7 +260,7 @@ public partial class MachineViewViewModel : ObservableObject
{ {
foreach(MemoryDto mem in machine.Memory) foreach(MemoryDto mem in machine.Memory)
{ {
long size = UntypedNodeExtractor.ExtractLong(mem.Size); long size = mem.Size ?? 0;
string sizeStr = size > 0 string sizeStr = size > 0
? size > 1024 ? $"{size} bytes ({size.Bytes().Humanize()})" : $"{size} bytes" ? size > 1024 ? $"{size} bytes ({size.Bytes().Humanize()})" : $"{size} bytes"
@@ -299,7 +298,7 @@ public partial class MachineViewViewModel : ObservableObject
foreach(SoundSynthDto synth in machine.SoundSynthesizers) foreach(SoundSynthDto synth in machine.SoundSynthesizers)
{ {
var details = new List<string>(); var details = new List<string>();
int voices = UntypedNodeExtractor.ExtractInt(synth.Voices); int voices = synth.Voices ?? 0;
if(voices > 0) details.Add($"{voices} voices"); if(voices > 0) details.Add($"{voices} voices");
@@ -317,7 +316,7 @@ public partial class MachineViewViewModel : ObservableObject
{ {
foreach(StorageDto storage in machine.Storage) foreach(StorageDto storage in machine.Storage)
{ {
long capacity = UntypedNodeExtractor.ExtractLong(storage.Capacity); long capacity = storage.Capacity ?? 0;
string displayText = capacity > 0 string displayText = capacity > 0
? capacity > 1024 ? capacity > 1024

View File

@@ -2,7 +2,6 @@ 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.Helpers;
using Marechai.App.Presentation.Models; using Marechai.App.Presentation.Models;
using Marechai.App.Services; using Marechai.App.Services;
using Marechai.Data; using Marechai.Data;
@@ -94,7 +93,7 @@ public partial class NewsViewModel : ObservableObject
// Extract the machine ID from AffectedId // Extract the machine ID from AffectedId
if(news.AffectedId is null) return; if(news.AffectedId is null) return;
int machineId = UntypedNodeExtractor.ExtractInt(news.AffectedId); int machineId = news.AffectedId ?? 0;
if(machineId <= 0) return; if(machineId <= 0) return;

View File

@@ -2,8 +2,6 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Marechai.App.Helpers;
using Microsoft.Kiota.Abstractions.Serialization;
namespace Marechai.App.Services; namespace Marechai.App.Services;
@@ -30,11 +28,9 @@ public class ComputersService
try try
{ {
_logger.LogInformation("Fetching computers count from API"); _logger.LogInformation("Fetching computers count from API");
UntypedNode result = await _apiClient.Computers.Count.GetAsync(); int? result = await _apiClient.Computers.Count.GetAsync();
// Extract integer value from UntypedNode int count = result ?? 0;
// UntypedNode wraps a JsonElement, we need to parse it
int count = UntypedNodeExtractor.ExtractInt(result);
_logger.LogInformation("Successfully fetched computers count: {Count}", count); _logger.LogInformation("Successfully fetched computers count: {Count}", count);
return count; return count;
@@ -56,10 +52,9 @@ public class ComputersService
try try
{ {
_logger.LogInformation("Fetching minimum year from API"); _logger.LogInformation("Fetching minimum year from API");
UntypedNode result = await _apiClient.Computers.MinimumYear.GetAsync(); int? result = await _apiClient.Computers.MinimumYear.GetAsync();
// Extract integer value from UntypedNode int year = result ?? 0;
int year = UntypedNodeExtractor.ExtractInt(result);
_logger.LogInformation("Successfully fetched minimum year: {Year}", year); _logger.LogInformation("Successfully fetched minimum year: {Year}", year);
return year; return year;
@@ -81,10 +76,9 @@ public class ComputersService
try try
{ {
_logger.LogInformation("Fetching maximum year from API"); _logger.LogInformation("Fetching maximum year from API");
UntypedNode result = await _apiClient.Computers.MaximumYear.GetAsync(); int? result = await _apiClient.Computers.MaximumYear.GetAsync();
// Extract integer value from UntypedNode int year = result ?? 0;
int year = UntypedNodeExtractor.ExtractInt(result);
_logger.LogInformation("Successfully fetched maximum year: {Year}", year); _logger.LogInformation("Successfully fetched maximum year: {Year}", year);
return year; return year;

View File

@@ -1,8 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Marechai.App.Helpers;
using Microsoft.Kiota.Abstractions.Serialization;
namespace Marechai.App.Services; namespace Marechai.App.Services;
@@ -29,11 +27,9 @@ public class ConsolesService
try try
{ {
_logger.LogInformation("Fetching consoles count from API"); _logger.LogInformation("Fetching consoles count from API");
UntypedNode result = await _apiClient.Consoles.Count.GetAsync(); int? result = await _apiClient.Consoles.Count.GetAsync();
// Extract integer value from UntypedNode int count = result ?? 0;
// UntypedNode wraps a JsonElement, we need to parse it
int count = UntypedNodeExtractor.ExtractInt(result);
_logger.LogInformation("Successfully fetched consoles count: {Count}", count); _logger.LogInformation("Successfully fetched consoles count: {Count}", count);
return count; return count;
@@ -55,10 +51,9 @@ public class ConsolesService
try try
{ {
_logger.LogInformation("Fetching minimum year from API"); _logger.LogInformation("Fetching minimum year from API");
UntypedNode result = await _apiClient.Consoles.MinimumYear.GetAsync(); int? result = await _apiClient.Consoles.MinimumYear.GetAsync();
// Extract integer value from UntypedNode int year = result ?? 0;
int year = UntypedNodeExtractor.ExtractInt(result);
_logger.LogInformation("Successfully fetched minimum year: {Year}", year); _logger.LogInformation("Successfully fetched minimum year: {Year}", year);
return year; return year;
@@ -80,10 +75,9 @@ public class ConsolesService
try try
{ {
_logger.LogInformation("Fetching maximum year from API"); _logger.LogInformation("Fetching maximum year from API");
UntypedNode result = await _apiClient.Consoles.MaximumYear.GetAsync(); int? result = await _apiClient.Consoles.MaximumYear.GetAsync();
// Extract integer value from UntypedNode int year = result ?? 0;
int year = UntypedNodeExtractor.ExtractInt(result);
_logger.LogInformation("Successfully fetched maximum year: {Year}", year); _logger.LogInformation("Successfully fetched maximum year: {Year}", year);
return year; return year;