diff --git a/Marechai.App/App.xaml.cs b/Marechai.App/App.xaml.cs index 0ba22de6..75abab11 100644 --- a/Marechai.App/App.xaml.cs +++ b/Marechai.App/App.xaml.cs @@ -2,6 +2,7 @@ using System.Net.Http; using Marechai.App.Presentation.ViewModels; using Marechai.App.Presentation.Views; using Marechai.App.Services; +using Marechai.App.Services.Caching; using Microsoft.UI.Xaml; using Uno.Extensions; using Uno.Extensions.Configuration; @@ -106,6 +107,7 @@ public partial class App : Application .ConfigureServices((context, services) => { // Register application services + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); diff --git a/Marechai.App/Marechai.App.csproj b/Marechai.App/Marechai.App.csproj index 9be6967d..bd744c02 100644 --- a/Marechai.App/Marechai.App.csproj +++ b/Marechai.App/Marechai.App.csproj @@ -36,6 +36,7 @@ Navigation; ThemeService; SkiaRenderer; + Svg; diff --git a/Marechai.App/Presentation/ViewModels/CompanyDetailViewModel.cs b/Marechai.App/Presentation/ViewModels/CompanyDetailViewModel.cs index b05d5748..0d5cb479 100644 --- a/Marechai.App/Presentation/ViewModels/CompanyDetailViewModel.cs +++ b/Marechai.App/Presentation/ViewModels/CompanyDetailViewModel.cs @@ -3,20 +3,25 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.IO; using System.Linq; using System.Threading.Tasks; using System.Windows.Input; using Marechai.App.Helpers; using Marechai.App.Presentation.Models; using Marechai.App.Services; +using Marechai.App.Services.Caching; using Marechai.Data; +using Microsoft.UI.Xaml.Media.Imaging; using Uno.Extensions.Navigation; +using Windows.Storage.Streams; namespace Marechai.App.Presentation.ViewModels; public partial class CompanyDetailViewModel : ObservableObject { private readonly CompanyDetailService _companyDetailService; + private readonly FlagCache _flagCache; private readonly IStringLocalizer _localizer; private readonly ILogger _logger; private readonly INavigator _navigator; @@ -57,13 +62,20 @@ public partial class CompanyDetailViewModel : ObservableObject [ObservableProperty] private bool _isLoading; + [ObservableProperty] + private SvgImageSource? _flagImageSource; + [ObservableProperty] private CompanyDto? _soldToCompany; - public CompanyDetailViewModel(CompanyDetailService companyDetailService, IStringLocalizer localizer, - ILogger logger, INavigator navigator) + public CompanyDetailViewModel(CompanyDetailService companyDetailService, + FlagCache flagCache, + IStringLocalizer localizer, + ILogger logger, + INavigator navigator) { _companyDetailService = companyDetailService; + _flagCache = flagCache; _localizer = localizer; _logger = logger; _navigator = navigator; @@ -82,6 +94,11 @@ public partial class CompanyDetailViewModel : ObservableObject /// public string CompanyFoundedDateDisplay => Company != null ? GetFoundedDateDisplay(Company) : string.Empty; + /// + /// Gets whether flag content is available + /// + public bool HasFlagContent => FlagImageSource != null; + public IAsyncRelayCommand LoadData { get; } public ICommand GoBackCommand { get; } public IAsyncRelayCommand NavigateToMachineCommand { get; } @@ -94,6 +111,12 @@ public partial class CompanyDetailViewModel : ObservableObject OnPropertyChanged(nameof(CompanyFoundedDateDisplay)); } + partial void OnFlagImageSourceChanged(SvgImageSource? oldValue, SvgImageSource? newValue) + { + // Notify that HasFlagContent has changed + OnPropertyChanged(nameof(HasFlagContent)); + } + partial void OnComputersFilterTextChanged(string value) { FilterComputers(value); @@ -286,6 +309,7 @@ public partial class CompanyDetailViewModel : ObservableObject ErrorMessage = string.Empty; HasError = false; IsDataLoaded = false; + FlagImageSource = null; if(CompanyId <= 0) { @@ -306,7 +330,28 @@ public partial class CompanyDetailViewModel : ObservableObject return; } - // Load sold-to company if applicable + // Load flag if country is available + if(Company.CountryId is not null) + { + try + { + short countryCode = (short)UntypedNodeExtractor.ExtractInt(Company.CountryId); + var flagStream = await _flagCache.GetFlagAsync(countryCode); + + var flagSource = new SvgImageSource(); + await flagSource.SetSourceAsync(flagStream.AsRandomAccessStream()); + FlagImageSource = flagSource; + + _logger.LogInformation("Successfully loaded flag for country code {CountryCode}", + countryCode); + } + catch(Exception ex) + { + _logger.LogError("Failed to load flag for country {CountryId}: {Exception}", + Company.CountryId, ex.Message); + // Continue without flag if loading fails + } + } if(Company.SoldToId != null) { int soldToId = UntypedNodeExtractor.ExtractInt(Company.SoldToId); diff --git a/Marechai.App/Presentation/Views/CompanyDetailPage.xaml b/Marechai.App/Presentation/Views/CompanyDetailPage.xaml index 8378831b..4ac597e0 100644 --- a/Marechai.App/Presentation/Views/CompanyDetailPage.xaml +++ b/Marechai.App/Presentation/Views/CompanyDetailPage.xaml @@ -7,6 +7,9 @@ NavigationCacheMode="Required" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> + + + @@ -113,14 +116,35 @@ - - + Padding="12"> + + + + + + + + + + + + + + + diff --git a/Marechai.App/Services/Caching/FlagCache.cs b/Marechai.App/Services/Caching/FlagCache.cs index b2107be4..000dc341 100644 --- a/Marechai.App/Services/Caching/FlagCache.cs +++ b/Marechai.App/Services/Caching/FlagCache.cs @@ -26,7 +26,7 @@ public sealed class FlagCache public async Task GetFlagAsync(short countryCode) { - var filename = $"{countryCode}.svg"; + var filename = $"{countryCode:D3}.svg"; Stream retStream; @@ -48,9 +48,9 @@ public sealed class FlagCache async Task CacheFlagAsync(short countryCode) { - var filename = $"{countryCode}.svg"; + var filename = $"{countryCode:D3}.svg"; string baseUrl = _configuration.GetSection("ApiClient:Url").Value; - string flagUrl = baseUrl + $"/assets/flags/{filename}"; + string flagUrl = baseUrl + $"/assets/flags/countries/{filename}"; using var httpClient = new HttpClient(); using HttpResponseMessage response = await httpClient.GetAsync(flagUrl); response.EnsureSuccessStatusCode();