mirror of
https://github.com/claunia/marechai.git
synced 2025-12-16 11:04:25 +00:00
Compare commits
13 Commits
955c2f9654
...
80791a8cc9
| Author | SHA1 | Date | |
|---|---|---|---|
|
80791a8cc9
|
|||
|
d5fbb55425
|
|||
|
7ee042bdec
|
|||
|
e9221ac130
|
|||
|
87291d9dd8
|
|||
|
ce1c089fb0
|
|||
|
5d249f435e
|
|||
|
3e4677b084
|
|||
|
b7c94312fc
|
|||
|
61ebf7b503
|
|||
|
b18396f8d8
|
|||
|
4f1aee302b
|
|||
|
7ede62514f
|
@@ -5,6 +5,7 @@
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<!-- Duplicated packages (also in Directory.Build.props) -->
|
||||
<PackageVersion Include="Humanizer" Version="2.14.1"/>
|
||||
<PackageVersion Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="9.0.11"/>
|
||||
<PackageVersion Include="Microsoft.EntityFrameworkCore.Proxies" Version="9.0.11"/>
|
||||
<!-- Unique to Marechai.csproj -->
|
||||
|
||||
@@ -1,19 +1,23 @@
|
||||
<Application x:Class="Marechai.App.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:Marechai.App.Presentation.Converters">
|
||||
|
||||
<Application.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<!-- Load WinUI resources -->
|
||||
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
|
||||
<!-- Load Uno.UI.Toolkit resources -->
|
||||
<ToolkitResources xmlns="using:Uno.Toolkit.UI" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
<Application.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<!-- Load WinUI resources -->
|
||||
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
|
||||
<!-- Load Uno.UI.Toolkit resources -->
|
||||
<ToolkitResources xmlns="using:Uno.Toolkit.UI" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<!-- Add resources here -->
|
||||
<!-- Add resources here -->
|
||||
<local:ObjectToVisibilityConverter x:Key="ObjectToVisibilityConverter" />
|
||||
<local:StringToVisibilityConverter x:Key="StringToVisibilityConverter" />
|
||||
<local:ZeroToVisibilityConverter x:Key="ZeroToVisibilityConverter" />
|
||||
|
||||
</ResourceDictionary>
|
||||
</Application.Resources>
|
||||
</ResourceDictionary>
|
||||
</Application.Resources>
|
||||
|
||||
</Application>
|
||||
</Application>
|
||||
@@ -1,4 +1,6 @@
|
||||
using System.Net.Http;
|
||||
using Marechai.App.Presentation.ViewModels;
|
||||
using Marechai.App.Presentation.Views;
|
||||
using Marechai.App.Services;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Uno.Extensions;
|
||||
@@ -8,6 +10,12 @@ using Uno.Extensions.Http;
|
||||
using Uno.Extensions.Localization;
|
||||
using Uno.Extensions.Navigation;
|
||||
using Uno.UI;
|
||||
using CompanyDetailViewModel = Marechai.App.Presentation.ViewModels.CompanyDetailViewModel;
|
||||
using ComputersListViewModel = Marechai.App.Presentation.ViewModels.ComputersListViewModel;
|
||||
using ComputersViewModel = Marechai.App.Presentation.ViewModels.ComputersViewModel;
|
||||
using MachineViewViewModel = Marechai.App.Presentation.ViewModels.MachineViewViewModel;
|
||||
using MainViewModel = Marechai.App.Presentation.ViewModels.MainViewModel;
|
||||
using NewsViewModel = Marechai.App.Presentation.ViewModels.NewsViewModel;
|
||||
|
||||
namespace Marechai.App;
|
||||
|
||||
@@ -100,6 +108,26 @@ public partial class App : Application
|
||||
// Register application services
|
||||
services.AddSingleton<NewsService>();
|
||||
services.AddSingleton<NewsViewModel>();
|
||||
services.AddSingleton<ComputersService>();
|
||||
services.AddSingleton<ComputersViewModel>();
|
||||
services.AddSingleton<ConsolesService>();
|
||||
services.AddSingleton<ConsolesViewModel>();
|
||||
services.AddSingleton<CompaniesService>();
|
||||
services.AddSingleton<CompaniesViewModel>();
|
||||
services.AddSingleton<CompanyDetailService>();
|
||||
services.AddSingleton<CompanyDetailViewModel>();
|
||||
services.AddSingleton<MachineViewViewModel>();
|
||||
|
||||
services
|
||||
.AddSingleton<IComputersListFilterContext,
|
||||
ComputersListFilterContext>();
|
||||
|
||||
services
|
||||
.AddSingleton<IConsolesListFilterContext,
|
||||
ConsolesListFilterContext>();
|
||||
|
||||
services.AddTransient<ComputersListViewModel>();
|
||||
services.AddTransient<ConsolesListViewModel>();
|
||||
})
|
||||
.UseNavigation(RegisterRoutes));
|
||||
|
||||
@@ -117,14 +145,58 @@ public partial class App : Application
|
||||
{
|
||||
views.Register(new ViewMap(ViewModel: typeof(ShellViewModel)),
|
||||
new ViewMap<MainPage, MainViewModel>(),
|
||||
new ViewMap<NewsPage, NewsViewModel>(),
|
||||
new ViewMap<ComputersPage, ComputersViewModel>(),
|
||||
new ViewMap<ComputersListPage, ComputersListViewModel>(),
|
||||
new ViewMap<ConsolesPage, ConsolesViewModel>(),
|
||||
new ViewMap<ConsolesListPage, ConsolesListViewModel>(),
|
||||
new ViewMap<CompaniesPage, CompaniesViewModel>(),
|
||||
new ViewMap<CompanyDetailPage, CompanyDetailViewModel>(),
|
||||
new ViewMap<MachineViewPage, MachineViewViewModel>(),
|
||||
new DataViewMap<SecondPage, SecondViewModel, Entity>());
|
||||
|
||||
routes.Register(new RouteMap("",
|
||||
views.FindByViewModel<ShellViewModel>(),
|
||||
Nested:
|
||||
[
|
||||
new RouteMap("Main", views.FindByViewModel<MainViewModel>(), true),
|
||||
new RouteMap("Second", views.FindByViewModel<SecondViewModel>())
|
||||
new RouteMap("Main",
|
||||
views.FindByViewModel<MainViewModel>(),
|
||||
true,
|
||||
Nested:
|
||||
[
|
||||
new RouteMap("News",
|
||||
views.FindByViewModel<NewsViewModel>(),
|
||||
true),
|
||||
new RouteMap("computers",
|
||||
views.FindByViewModel<ComputersViewModel>(),
|
||||
Nested:
|
||||
[
|
||||
new RouteMap("list-computers",
|
||||
views.FindByViewModel<
|
||||
ComputersListViewModel>()),
|
||||
new RouteMap("view",
|
||||
views.FindByViewModel<
|
||||
MachineViewViewModel>())
|
||||
]),
|
||||
new RouteMap("consoles",
|
||||
views.FindByViewModel<ConsolesViewModel>(),
|
||||
Nested:
|
||||
[
|
||||
new RouteMap("list-consoles",
|
||||
views.FindByViewModel<
|
||||
ConsolesListViewModel>())
|
||||
]),
|
||||
new RouteMap("companies",
|
||||
views.FindByViewModel<CompaniesViewModel>(),
|
||||
Nested:
|
||||
[
|
||||
new RouteMap("detail",
|
||||
views.FindByViewModel<
|
||||
CompanyDetailViewModel>())
|
||||
]),
|
||||
new RouteMap("Second",
|
||||
views.FindByViewModel<SecondViewModel>())
|
||||
])
|
||||
]));
|
||||
}
|
||||
}
|
||||
61
Marechai.App/Helpers/UntypedNodeExtractor.cs
Normal file
61
Marechai.App/Helpers/UntypedNodeExtractor.cs
Normal file
@@ -0,0 +1,61 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,5 +41,42 @@
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Marechai.Data\Marechai.Data.csproj"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Humanizer"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Update="Presentation\Views\Shell.xaml.cs">
|
||||
<DependentUpon>Shell.xaml</DependentUpon>
|
||||
<IsDefaultItem>true</IsDefaultItem>
|
||||
</Compile>
|
||||
<Compile Update="Presentation\Views\SecondPage.xaml.cs">
|
||||
<DependentUpon>SecondPage.xaml</DependentUpon>
|
||||
<IsDefaultItem>true</IsDefaultItem>
|
||||
</Compile>
|
||||
<Compile Update="Presentation\Views\ComputersPage.xaml.cs">
|
||||
<DependentUpon>ComputersPage.xaml</DependentUpon>
|
||||
<IsDefaultItem>true</IsDefaultItem>
|
||||
</Compile>
|
||||
<Compile Update="Presentation\Views\MainPage.xaml.cs">
|
||||
<DependentUpon>MainPage.xaml</DependentUpon>
|
||||
<IsDefaultItem>true</IsDefaultItem>
|
||||
</Compile>
|
||||
<Compile Update="Presentation\Views\ComputersListPage.xaml.cs">
|
||||
<DependentUpon>ComputersListPage.xaml</DependentUpon>
|
||||
<IsDefaultItem>true</IsDefaultItem>
|
||||
</Compile>
|
||||
<Compile Update="Presentation\Views\NewsPage.xaml.cs">
|
||||
<DependentUpon>NewsPage.xaml</DependentUpon>
|
||||
<IsDefaultItem>true</IsDefaultItem>
|
||||
</Compile>
|
||||
<Compile Update="Presentation\Views\MachineViewPage.xaml.cs">
|
||||
<DependentUpon>MachineViewPage.xaml</DependentUpon>
|
||||
<IsDefaultItem>true</IsDefaultItem>
|
||||
</Compile>
|
||||
<Compile Update="Presentation\Components\Sidebar.xaml.cs">
|
||||
<DependentUpon>Sidebar.xaml</DependentUpon>
|
||||
<IsDefaultItem>true</IsDefaultItem>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
260
Marechai.App/Presentation/Components/Sidebar.xaml
Normal file
260
Marechai.App/Presentation/Components/Sidebar.xaml
Normal file
@@ -0,0 +1,260 @@
|
||||
<?xml version="1.0"
|
||||
encoding="utf-8"?>
|
||||
|
||||
<UserControl x:Class="Marechai.App.Presentation.Components.Sidebar"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="using:Marechai.App.Presentation.Converters"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="600"
|
||||
d:DesignWidth="280"
|
||||
Background="{ThemeResource NavigationViewDefaultPaneBackground}">
|
||||
<UserControl.Resources>
|
||||
<local:CollapseExpandIconConverter x:Key="CollapseExpandIconConverter" />
|
||||
<local:CollapseExpandTooltipConverter x:Key="CollapseExpandTooltipConverter" />
|
||||
</UserControl.Resources>
|
||||
|
||||
<!-- Grid container - naturally responds to parent column width -->
|
||||
<Grid RowSpacing="0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" /> <RowDefinition Height="*" /> <RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Sidebar Header with Collapse/Expand Button -->
|
||||
<Grid Grid.Row="0"
|
||||
Padding="8,8,8,8"
|
||||
BorderBrush="{ThemeResource DividerStrokeColorDefaultBrush}"
|
||||
BorderThickness="0,0,0,1">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" /> <ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- Sidebar Title - Hidden when collapsed -->
|
||||
<TextBlock Grid.Column="0"
|
||||
Text="Navigation"
|
||||
FontSize="16"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{ThemeResource TextFillColorPrimaryBrush}"
|
||||
VerticalAlignment="Center"
|
||||
Padding="4,0,0,0"
|
||||
Visibility="{Binding SidebarContentVisible}" />
|
||||
|
||||
<!-- Collapse/Expand Button - Always visible -->
|
||||
<Button Grid.Column="1"
|
||||
Content="{Binding IsSidebarOpen, Converter={StaticResource CollapseExpandIconConverter}}"
|
||||
Command="{Binding ToggleSidebarCommand}"
|
||||
Background="Transparent"
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||
Padding="8,8,8,8"
|
||||
CornerRadius="4"
|
||||
ToolTipService.ToolTip="{Binding IsSidebarOpen, Converter={StaticResource CollapseExpandTooltipConverter}}"
|
||||
FontSize="14"
|
||||
MinWidth="40"
|
||||
MinHeight="40"
|
||||
HorizontalAlignment="Center" />
|
||||
</Grid>
|
||||
|
||||
<!-- Scrollable Navigation Items - Hidden when collapsed -->
|
||||
<ScrollViewer Grid.Row="1"
|
||||
VerticalScrollBarVisibility="Auto"
|
||||
HorizontalScrollBarVisibility="Disabled"
|
||||
Padding="0"
|
||||
Visibility="{Binding SidebarContentVisible}">
|
||||
<StackPanel Orientation="Vertical"
|
||||
Spacing="0"
|
||||
Padding="0">
|
||||
<!-- News -->
|
||||
<Button Content="{Binding LocalizedStrings[News]}"
|
||||
Command="{Binding NavigateToNewsCommand}"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Left"
|
||||
Padding="16,10,16,10"
|
||||
FontSize="13"
|
||||
Background="Transparent"
|
||||
Foreground="{ThemeResource TextFillColorPrimaryBrush}"
|
||||
BorderThickness="0"
|
||||
CornerRadius="0" />
|
||||
|
||||
<!-- Books -->
|
||||
<Button Content="{Binding LocalizedStrings[Books]}"
|
||||
Command="{Binding NavigateToBooksCommand}"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Left"
|
||||
Padding="16,10,16,10"
|
||||
FontSize="13"
|
||||
Background="Transparent"
|
||||
Foreground="{ThemeResource TextFillColorPrimaryBrush}"
|
||||
BorderThickness="0"
|
||||
CornerRadius="0" />
|
||||
|
||||
<!-- Companies -->
|
||||
<Button Content="{Binding LocalizedStrings[Companies]}"
|
||||
Command="{Binding NavigateToCompaniesCommand}"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Left"
|
||||
Padding="16,10,16,10"
|
||||
FontSize="13"
|
||||
Background="Transparent"
|
||||
Foreground="{ThemeResource TextFillColorPrimaryBrush}"
|
||||
BorderThickness="0"
|
||||
CornerRadius="0" />
|
||||
|
||||
<!-- Computers -->
|
||||
<Button Content="{Binding LocalizedStrings[Computers]}"
|
||||
Command="{Binding NavigateToComputersCommand}"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Left"
|
||||
Padding="16,10,16,10"
|
||||
FontSize="13"
|
||||
Background="Transparent"
|
||||
Foreground="{ThemeResource TextFillColorPrimaryBrush}"
|
||||
BorderThickness="0"
|
||||
CornerRadius="0" />
|
||||
|
||||
<!-- Consoles -->
|
||||
<Button Content="{Binding LocalizedStrings[Consoles]}"
|
||||
Command="{Binding NavigateToConsolesCommand}"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Left"
|
||||
Padding="16,10,16,10"
|
||||
FontSize="13"
|
||||
Background="Transparent"
|
||||
Foreground="{ThemeResource TextFillColorPrimaryBrush}"
|
||||
BorderThickness="0"
|
||||
CornerRadius="0" />
|
||||
|
||||
<!-- Documents -->
|
||||
<Button Content="{Binding LocalizedStrings[Documents]}"
|
||||
Command="{Binding NavigateToDocumentsCommand}"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Left"
|
||||
Padding="16,10,16,10"
|
||||
FontSize="13"
|
||||
Background="Transparent"
|
||||
Foreground="{ThemeResource TextFillColorPrimaryBrush}"
|
||||
BorderThickness="0"
|
||||
CornerRadius="0" />
|
||||
|
||||
<!-- Dumps -->
|
||||
<Button Content="{Binding LocalizedStrings[Dumps]}"
|
||||
Command="{Binding NavigateToDumpsCommand}"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Left"
|
||||
Padding="16,10,16,10"
|
||||
FontSize="13"
|
||||
Background="Transparent"
|
||||
Foreground="{ThemeResource TextFillColorPrimaryBrush}"
|
||||
BorderThickness="0"
|
||||
CornerRadius="0" />
|
||||
|
||||
<!-- Graphical Processing Units -->
|
||||
<Button Content="{Binding LocalizedStrings[GraphicalProcessingUnits]}"
|
||||
Command="{Binding NavigateToGraphicalProcessingUnitsCommand}"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Left"
|
||||
Padding="16,10,16,10"
|
||||
FontSize="13"
|
||||
Background="Transparent"
|
||||
Foreground="{ThemeResource TextFillColorPrimaryBrush}"
|
||||
BorderThickness="0"
|
||||
CornerRadius="0" />
|
||||
|
||||
<!-- Magazines -->
|
||||
<Button Content="{Binding LocalizedStrings[Magazines]}"
|
||||
Command="{Binding NavigateToMagazinesCommand}"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Left"
|
||||
Padding="16,10,16,10"
|
||||
FontSize="13"
|
||||
Background="Transparent"
|
||||
Foreground="{ThemeResource TextFillColorPrimaryBrush}"
|
||||
BorderThickness="0"
|
||||
CornerRadius="0" />
|
||||
|
||||
<!-- People -->
|
||||
<Button Content="{Binding LocalizedStrings[People]}"
|
||||
Command="{Binding NavigateToPeopleCommand}"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Left"
|
||||
Padding="16,10,16,10"
|
||||
FontSize="13"
|
||||
Background="Transparent"
|
||||
Foreground="{ThemeResource TextFillColorPrimaryBrush}"
|
||||
BorderThickness="0"
|
||||
CornerRadius="0" />
|
||||
|
||||
<!-- Processors -->
|
||||
<Button Content="{Binding LocalizedStrings[Processors]}"
|
||||
Command="{Binding NavigateToProcessorsCommand}"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Left"
|
||||
Padding="16,10,16,10"
|
||||
FontSize="13"
|
||||
Background="Transparent"
|
||||
Foreground="{ThemeResource TextFillColorPrimaryBrush}"
|
||||
BorderThickness="0"
|
||||
CornerRadius="0" />
|
||||
|
||||
<!-- Software -->
|
||||
<Button Content="{Binding LocalizedStrings[Software]}"
|
||||
Command="{Binding NavigateToSoftwareCommand}"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Left"
|
||||
Padding="16,10,16,10"
|
||||
FontSize="13"
|
||||
Background="Transparent"
|
||||
Foreground="{ThemeResource TextFillColorPrimaryBrush}"
|
||||
BorderThickness="0"
|
||||
CornerRadius="0" />
|
||||
|
||||
<!-- Sound Synthesizers -->
|
||||
<Button Content="{Binding LocalizedStrings[SoundSynthesizers]}"
|
||||
Command="{Binding NavigateToSoundSynthesizersCommand}"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Left"
|
||||
Padding="16,10,16,10"
|
||||
FontSize="13"
|
||||
Background="Transparent"
|
||||
Foreground="{ThemeResource TextFillColorPrimaryBrush}"
|
||||
BorderThickness="0"
|
||||
CornerRadius="0" />
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
|
||||
<!-- Bottom Fixed Items - Hidden when collapsed -->
|
||||
<Grid Grid.Row="2"
|
||||
BorderBrush="{ThemeResource DividerStrokeColorDefaultBrush}"
|
||||
BorderThickness="0,1,0,0"
|
||||
Padding="0"
|
||||
Visibility="{Binding IsSidebarOpen}">
|
||||
<StackPanel Orientation="Vertical"
|
||||
Spacing="0">
|
||||
<!-- Login/Logout -->
|
||||
<Button Content="{Binding LoginLogoutButtonText}"
|
||||
Command="{Binding LoginLogoutCommand}"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Left"
|
||||
Padding="16,10,16,10"
|
||||
FontSize="13"
|
||||
Background="Transparent"
|
||||
Foreground="{ThemeResource TextFillColorPrimaryBrush}"
|
||||
BorderThickness="0"
|
||||
CornerRadius="0" />
|
||||
|
||||
<!-- Settings -->
|
||||
<Button Content="{Binding LocalizedStrings[Settings]}"
|
||||
Command="{Binding NavigateToSettingsCommand}"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Left"
|
||||
Padding="16,10,16,10"
|
||||
FontSize="13"
|
||||
Background="Transparent"
|
||||
Foreground="{ThemeResource TextFillColorPrimaryBrush}"
|
||||
BorderThickness="0"
|
||||
CornerRadius="0" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
11
Marechai.App/Presentation/Components/Sidebar.xaml.cs
Normal file
11
Marechai.App/Presentation/Components/Sidebar.xaml.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Marechai.App.Presentation.Components;
|
||||
|
||||
public sealed partial class Sidebar : UserControl
|
||||
{
|
||||
public Sidebar()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
51
Marechai.App/Presentation/Converters/CompanyConverters.cs
Normal file
51
Marechai.App/Presentation/Converters/CompanyConverters.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
using System;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Data;
|
||||
|
||||
namespace Marechai.App.Presentation.Converters;
|
||||
|
||||
/// <summary>
|
||||
/// Converts null object to Collapsed visibility
|
||||
/// </summary>
|
||||
public class ObjectToVisibilityConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, string language) =>
|
||||
value != null ? Visibility.Visible : Visibility.Collapsed;
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, string language) =>
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts empty/null string to Collapsed visibility
|
||||
/// </summary>
|
||||
public class StringToVisibilityConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
if(value is string str && !string.IsNullOrWhiteSpace(str)) return Visibility.Visible;
|
||||
|
||||
return Visibility.Collapsed;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, string language) =>
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts zero count to Collapsed visibility, otherwise Visible
|
||||
/// </summary>
|
||||
public class ZeroToVisibilityConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
if(value is int count && count > 0) return Visibility.Visible;
|
||||
|
||||
if(value is long longCount && longCount > 0) return Visibility.Visible;
|
||||
|
||||
return Visibility.Collapsed;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, string language) =>
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using Microsoft.UI.Xaml.Data;
|
||||
|
||||
namespace Marechai.App.Presentation.Converters;
|
||||
|
||||
/// <summary>
|
||||
/// Converts DateTime to formatted foundation date string, returns empty if null
|
||||
/// </summary>
|
||||
public class FoundationDateConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
if(value is DateTime dateTime) return dateTime.ToString("MMMM d, yyyy");
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, string language) =>
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
59
Marechai.App/Presentation/Converters/SidebarConverters.cs
Normal file
59
Marechai.App/Presentation/Converters/SidebarConverters.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
using System;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Data;
|
||||
|
||||
namespace Marechai.App.Presentation.Converters;
|
||||
|
||||
/// <summary>
|
||||
/// Converts boolean value to collapse/expand arrow icon
|
||||
/// </summary>
|
||||
public class CollapseExpandIconConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
if(value is bool isOpen) return isOpen ? "◄" : "►";
|
||||
|
||||
return "►";
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, string language) =>
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts boolean value to collapse/expand tooltip text
|
||||
/// </summary>
|
||||
public class CollapseExpandTooltipConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
if(value is bool isOpen) return isOpen ? "Collapse Sidebar" : "Expand Sidebar";
|
||||
|
||||
return "Expand Sidebar";
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, string language) =>
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts boolean value to GridLength for sidebar column width
|
||||
/// </summary>
|
||||
public class SidebarWidthConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
if(value is bool isOpen)
|
||||
{
|
||||
// 280 when open, 60 when collapsed (to keep toggle button visible)
|
||||
double width = isOpen ? 280 : 60;
|
||||
|
||||
return new GridLength(width, GridUnitType.Pixel);
|
||||
}
|
||||
|
||||
return new GridLength(280, GridUnitType.Pixel);
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, string language) =>
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
using System;
|
||||
using Windows.Foundation;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
|
||||
namespace Marechai.App.Presentation;
|
||||
|
||||
public sealed partial class MainPage : Page
|
||||
{
|
||||
private bool _initialNewsLoaded;
|
||||
|
||||
public MainPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContextChanged += MainPage_DataContextChanged;
|
||||
}
|
||||
|
||||
private void MainPage_DataContextChanged(FrameworkElement sender, DataContextChangedEventArgs args)
|
||||
{
|
||||
if(_initialNewsLoaded) return;
|
||||
|
||||
if(args.NewValue is MainViewModel viewModel && viewModel.NewsViewModel is not null)
|
||||
{
|
||||
_initialNewsLoaded = true;
|
||||
_ = viewModel.NewsViewModel.LoadNews.ExecuteAsync(null);
|
||||
DataContextChanged -= MainPage_DataContextChanged;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
base.OnNavigatedTo(e);
|
||||
|
||||
if(_initialNewsLoaded) return;
|
||||
|
||||
if(DataContext is MainViewModel viewModel && viewModel.NewsViewModel is not null)
|
||||
{
|
||||
_initialNewsLoaded = true;
|
||||
_ = viewModel.NewsViewModel.LoadNews.ExecuteAsync(null);
|
||||
DataContextChanged -= MainPage_DataContextChanged;
|
||||
}
|
||||
}
|
||||
|
||||
private async void RefreshContainer_RefreshRequested(RefreshContainer sender, RefreshRequestedEventArgs args)
|
||||
{
|
||||
// Handle pull-to-refresh
|
||||
using Deferral deferral = args.GetDeferral();
|
||||
|
||||
try
|
||||
{
|
||||
if(DataContext is MainViewModel viewModel && viewModel.NewsViewModel is not null)
|
||||
await viewModel.NewsViewModel.LoadNews.ExecuteAsync(null);
|
||||
}
|
||||
catch(Exception)
|
||||
{
|
||||
// Swallow to avoid process crash; NewsViewModel already logs errors.
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using Uno.Extensions.Navigation;
|
||||
|
||||
namespace Marechai.App.Presentation;
|
||||
|
||||
public partial class MainViewModel : ObservableObject
|
||||
{
|
||||
private readonly INavigator _navigator;
|
||||
|
||||
[ObservableProperty]
|
||||
private string? name;
|
||||
[ObservableProperty]
|
||||
private NewsViewModel? newsViewModel;
|
||||
|
||||
public MainViewModel(IStringLocalizer localizer, IOptions<AppConfig> appInfo, INavigator navigator,
|
||||
NewsViewModel newsViewModel)
|
||||
{
|
||||
_navigator = navigator;
|
||||
NewsViewModel = newsViewModel;
|
||||
Title = "Marechai";
|
||||
Title += $" - {localizer["ApplicationName"]}";
|
||||
Title += $" - {appInfo?.Value?.Environment}";
|
||||
GoToSecond = new AsyncRelayCommand(GoToSecondView);
|
||||
}
|
||||
|
||||
public string? Title { get; }
|
||||
|
||||
public ICommand GoToSecond { get; }
|
||||
|
||||
private async Task GoToSecondView()
|
||||
{
|
||||
await _navigator.NavigateViewModelAsync<SecondViewModel>(this, data: new Entity(Name!));
|
||||
}
|
||||
}
|
||||
@@ -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 CompanyDetailPage containing both the company ID and the navigation source.
|
||||
/// </summary>
|
||||
public class CompanyDetailNavigationParameter
|
||||
{
|
||||
public required int CompanyId { get; init; }
|
||||
public object? NavigationSource { get; init; }
|
||||
}
|
||||
@@ -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 MachineViewPage containing both the machine ID and the navigation source.
|
||||
/// </summary>
|
||||
public class MachineViewNavigationParameter
|
||||
{
|
||||
public required int MachineId { get; init; }
|
||||
public object? NavigationSource { get; init; }
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Threading.Tasks;
|
||||
using Marechai.App.Services;
|
||||
using Marechai.Data;
|
||||
|
||||
namespace Marechai.App.Presentation;
|
||||
|
||||
/// <summary>
|
||||
/// Wrapper for NewsDto with generated display text
|
||||
/// </summary>
|
||||
public class NewsItemViewModel
|
||||
{
|
||||
public required NewsDto News { get; init; }
|
||||
public required string DisplayText { get; init; }
|
||||
}
|
||||
|
||||
public partial class NewsViewModel : ObservableObject
|
||||
{
|
||||
private readonly IStringLocalizer _localizer;
|
||||
private readonly ILogger<NewsViewModel> _logger;
|
||||
private readonly NewsService _newsService;
|
||||
|
||||
[ObservableProperty]
|
||||
private string errorMessage = string.Empty;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool hasError;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool isLoading;
|
||||
|
||||
[ObservableProperty]
|
||||
private ObservableCollection<NewsItemViewModel> newsList = new();
|
||||
|
||||
public NewsViewModel(NewsService newsService, IStringLocalizer localizer, ILogger<NewsViewModel> logger)
|
||||
{
|
||||
_newsService = newsService;
|
||||
_localizer = localizer;
|
||||
_logger = logger;
|
||||
LoadNews = new AsyncRelayCommand(LoadNewsAsync);
|
||||
}
|
||||
|
||||
public IAsyncRelayCommand LoadNews { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Generates localized text based on NewsType
|
||||
/// </summary>
|
||||
private string GetLocalizedTextForNewsType(NewsType type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
NewsType.NewComputerInDb => _localizer["New computer in database"].Value,
|
||||
NewsType.NewConsoleInDb => _localizer["New console in database"].Value,
|
||||
NewsType.NewComputerInCollection => _localizer["New computer in collection"].Value,
|
||||
NewsType.NewConsoleInCollection => _localizer["New console in collection"].Value,
|
||||
NewsType.UpdatedComputerInDb => _localizer["Updated computer in database"].Value,
|
||||
NewsType.UpdatedConsoleInDb => _localizer["Updated console in database"].Value,
|
||||
NewsType.UpdatedComputerInCollection => _localizer["Updated computer in collection"].Value,
|
||||
NewsType.UpdatedConsoleInCollection => _localizer["Updated console in collection"].Value,
|
||||
_ => string.Empty
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads the latest news from the API
|
||||
/// </summary>
|
||||
private async Task LoadNewsAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
IsLoading = true;
|
||||
ErrorMessage = string.Empty;
|
||||
HasError = false;
|
||||
NewsList.Clear();
|
||||
|
||||
List<NewsDto> news = await _newsService.GetLatestNewsAsync();
|
||||
|
||||
if(news.Count == 0)
|
||||
{
|
||||
ErrorMessage = _localizer["No news available"].Value;
|
||||
HasError = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach(NewsDto item in news)
|
||||
{
|
||||
NewsList.Add(new NewsItemViewModel
|
||||
{
|
||||
News = item,
|
||||
DisplayText = GetLocalizedTextForNewsType((NewsType)(item.Type ?? 0))
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError("Error loading news: {Exception}", ex.Message);
|
||||
ErrorMessage = _localizer["Failed to load news. Please try again later."].Value;
|
||||
HasError = true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsLoading = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
<Page x:Class="Marechai.App.Presentation.SecondPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:Marechai.App.Presentation"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:uen="using:Uno.Extensions.Navigation.UI"
|
||||
xmlns:utu="using:Uno.Toolkit.UI"
|
||||
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
|
||||
<Grid utu:SafeArea.Insets="VisibleBounds">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<utu:NavigationBar Content="Second Page" />
|
||||
<StackPanel Grid.Row="1"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center">
|
||||
<TextBlock Text="{Binding Entity.Name}"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Margin="8" />
|
||||
</StackPanel>
|
||||
|
||||
</Grid>
|
||||
</Page>
|
||||
@@ -1,5 +0,0 @@
|
||||
namespace Marechai.App.Presentation;
|
||||
|
||||
public partial record SecondViewModel(Entity Entity)
|
||||
{
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
<UserControl x:Class="Marechai.App.Presentation.Shell"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:Marechai.App.Presentation"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:utu="using:Uno.Toolkit.UI"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="300"
|
||||
d:DesignWidth="400">
|
||||
<Border Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
<utu:ExtendedSplashScreen x:Name="Splash"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
VerticalContentAlignment="Stretch">
|
||||
<utu:ExtendedSplashScreen.LoadingContentTemplate>
|
||||
<DataTemplate>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="2*" />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<ProgressRing IsActive="True"
|
||||
Grid.Row="1"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center"
|
||||
Height="100"
|
||||
Width="100" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</utu:ExtendedSplashScreen.LoadingContentTemplate>
|
||||
</utu:ExtendedSplashScreen>
|
||||
</Border>
|
||||
</UserControl>
|
||||
@@ -1,15 +0,0 @@
|
||||
using Uno.Extensions.Navigation;
|
||||
|
||||
namespace Marechai.App.Presentation;
|
||||
|
||||
public class ShellViewModel
|
||||
{
|
||||
private readonly INavigator _navigator;
|
||||
|
||||
public ShellViewModel(
|
||||
INavigator navigator)
|
||||
{
|
||||
_navigator = navigator;
|
||||
// Add code here to initialize or attach event handlers to singleton services
|
||||
}
|
||||
}
|
||||
195
Marechai.App/Presentation/ViewModels/CompaniesViewModel.cs
Normal file
195
Marechai.App/Presentation/ViewModels/CompaniesViewModel.cs
Normal file
@@ -0,0 +1,195 @@
|
||||
#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.Helpers;
|
||||
using Marechai.App.Presentation.Models;
|
||||
using Marechai.App.Services;
|
||||
using Uno.Extensions.Navigation;
|
||||
|
||||
namespace Marechai.App.Presentation.ViewModels;
|
||||
|
||||
public partial class CompaniesViewModel : ObservableObject
|
||||
{
|
||||
private readonly List<CompanyListItem> _allCompanies = [];
|
||||
private readonly CompaniesService _companiesService;
|
||||
private readonly IStringLocalizer _localizer;
|
||||
private readonly ILogger<CompaniesViewModel> _logger;
|
||||
private readonly INavigator _navigator;
|
||||
|
||||
[ObservableProperty]
|
||||
private ObservableCollection<CompanyListItem> _companiesList = [];
|
||||
|
||||
[ObservableProperty]
|
||||
private int _companyCount;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _companyCountText = string.Empty;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _errorMessage = string.Empty;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _hasError;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _isDataLoaded;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _isLoading;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _searchQuery = string.Empty;
|
||||
|
||||
public CompaniesViewModel(CompaniesService companiesService, IStringLocalizer localizer,
|
||||
ILogger<CompaniesViewModel> logger, INavigator navigator)
|
||||
{
|
||||
_companiesService = companiesService;
|
||||
_localizer = localizer;
|
||||
_logger = logger;
|
||||
_navigator = navigator;
|
||||
LoadData = new AsyncRelayCommand(LoadDataAsync);
|
||||
GoBackCommand = new AsyncRelayCommand(GoBackAsync);
|
||||
NavigateToCompanyCommand = new AsyncRelayCommand<CompanyListItem>(NavigateToCompanyAsync);
|
||||
}
|
||||
|
||||
public IAsyncRelayCommand LoadData { get; }
|
||||
public ICommand GoBackCommand { get; }
|
||||
public IAsyncRelayCommand<CompanyListItem> NavigateToCompanyCommand { get; }
|
||||
public string Title { get; } = "Companies";
|
||||
|
||||
partial void OnSearchQueryChanged(string value)
|
||||
{
|
||||
// Automatically filter when SearchQuery changes
|
||||
UpdateFilter(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads companies count and list from the API
|
||||
/// </summary>
|
||||
private async Task LoadDataAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
IsLoading = true;
|
||||
ErrorMessage = string.Empty;
|
||||
HasError = false;
|
||||
IsDataLoaded = false;
|
||||
CompaniesList.Clear();
|
||||
_allCompanies.Clear();
|
||||
|
||||
// Load companies
|
||||
List<CompanyDto> companies = await _companiesService.GetAllCompaniesAsync();
|
||||
|
||||
// Set count
|
||||
CompanyCount = companies.Count;
|
||||
CompanyCountText = _localizer["Companies in the database"];
|
||||
|
||||
// Build the full list in memory
|
||||
foreach(CompanyDto company in companies)
|
||||
{
|
||||
// Extract id from UntypedNode
|
||||
int companyId = UntypedNodeExtractor.ExtractInt(company.Id);
|
||||
|
||||
// Convert DateTimeOffset? to DateTime?
|
||||
DateTime? foundedDate = company.Founded?.DateTime;
|
||||
|
||||
_allCompanies.Add(new CompanyListItem
|
||||
{
|
||||
Id = companyId,
|
||||
Name = company.Name ?? string.Empty,
|
||||
FoundationDate = foundedDate
|
||||
});
|
||||
}
|
||||
|
||||
// Apply current filter (will show all if SearchQuery is empty)
|
||||
UpdateFilter(SearchQuery);
|
||||
|
||||
if(CompaniesList.Count == 0)
|
||||
{
|
||||
ErrorMessage = _localizer["No companies found"].Value;
|
||||
HasError = true;
|
||||
}
|
||||
else
|
||||
IsDataLoaded = true;
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError("Error loading companies data: {Exception}", ex.Message);
|
||||
ErrorMessage = _localizer["Failed to load companies data. Please try again later."].Value;
|
||||
HasError = true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles back navigation
|
||||
/// </summary>
|
||||
private async Task GoBackAsync()
|
||||
{
|
||||
await _navigator.NavigateViewModelAsync<MainViewModel>(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Navigates to company detail view
|
||||
/// </summary>
|
||||
private async Task NavigateToCompanyAsync(CompanyListItem? company)
|
||||
{
|
||||
if(company is null) return;
|
||||
|
||||
_logger.LogInformation("Navigating to company: {CompanyName} (ID: {CompanyId})", company.Name, company.Id);
|
||||
|
||||
// Navigate to company detail view with navigation parameter
|
||||
var navParam = new CompanyDetailNavigationParameter
|
||||
{
|
||||
CompanyId = company.Id,
|
||||
NavigationSource = this
|
||||
};
|
||||
|
||||
await _navigator.NavigateViewModelAsync<CompanyDetailViewModel>(this, data: navParam);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the filtered list based on search query
|
||||
/// </summary>
|
||||
private void UpdateFilter(string? query)
|
||||
{
|
||||
string lowerQuery = string.IsNullOrWhiteSpace(query) ? string.Empty : query.Trim().ToLowerInvariant();
|
||||
|
||||
CompaniesList.Clear();
|
||||
|
||||
if(string.IsNullOrEmpty(lowerQuery))
|
||||
{
|
||||
// No filter, show all companies
|
||||
foreach(CompanyListItem company in _allCompanies) CompaniesList.Add(company);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Filter companies by name (case-insensitive)
|
||||
var filtered = _allCompanies.Where(c => c.Name.Contains(lowerQuery, StringComparison.OrdinalIgnoreCase))
|
||||
.ToList();
|
||||
|
||||
foreach(CompanyListItem company in filtered) CompaniesList.Add(company);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Data model for a company in the list
|
||||
/// </summary>
|
||||
public class CompanyListItem
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public DateTime? FoundationDate { get; set; }
|
||||
|
||||
public string FoundationDateDisplay =>
|
||||
FoundationDate.HasValue ? FoundationDate.Value.ToString("MMMM d, yyyy") : string.Empty;
|
||||
}
|
||||
373
Marechai.App/Presentation/ViewModels/CompanyDetailViewModel.cs
Normal file
373
Marechai.App/Presentation/ViewModels/CompanyDetailViewModel.cs
Normal file
@@ -0,0 +1,373 @@
|
||||
#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.Helpers;
|
||||
using Marechai.App.Presentation.Models;
|
||||
using Marechai.App.Services;
|
||||
using Marechai.Data;
|
||||
using Uno.Extensions.Navigation;
|
||||
|
||||
namespace Marechai.App.Presentation.ViewModels;
|
||||
|
||||
public partial class CompanyDetailViewModel : ObservableObject
|
||||
{
|
||||
private readonly CompanyDetailService _companyDetailService;
|
||||
private readonly IStringLocalizer _localizer;
|
||||
private readonly ILogger<CompanyDetailViewModel> _logger;
|
||||
private readonly INavigator _navigator;
|
||||
|
||||
[ObservableProperty]
|
||||
private CompanyDto? _company;
|
||||
|
||||
[ObservableProperty]
|
||||
private int _companyId;
|
||||
|
||||
[ObservableProperty]
|
||||
private ObservableCollection<CompanyDetailMachine> _computers = [];
|
||||
|
||||
[ObservableProperty]
|
||||
private string _computersFilterText = string.Empty;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _consoelsFilterText = string.Empty;
|
||||
|
||||
[ObservableProperty]
|
||||
private ObservableCollection<CompanyDetailMachine> _consoles = [];
|
||||
|
||||
[ObservableProperty]
|
||||
private string _errorMessage = string.Empty;
|
||||
|
||||
[ObservableProperty]
|
||||
private ObservableCollection<CompanyDetailMachine> _filteredComputers = [];
|
||||
|
||||
[ObservableProperty]
|
||||
private ObservableCollection<CompanyDetailMachine> _filteredConsoles = [];
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _hasError;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _isDataLoaded;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _isLoading;
|
||||
|
||||
[ObservableProperty]
|
||||
private CompanyDto? _soldToCompany;
|
||||
|
||||
public CompanyDetailViewModel(CompanyDetailService companyDetailService, IStringLocalizer localizer,
|
||||
ILogger<CompanyDetailViewModel> logger, INavigator navigator)
|
||||
{
|
||||
_companyDetailService = companyDetailService;
|
||||
_localizer = localizer;
|
||||
_logger = logger;
|
||||
_navigator = navigator;
|
||||
LoadData = new AsyncRelayCommand(LoadDataAsync);
|
||||
GoBackCommand = new AsyncRelayCommand(GoBackAsync);
|
||||
NavigateToMachineCommand = new AsyncRelayCommand<CompanyDetailMachine>(NavigateToMachineAsync);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the display text for the company's status
|
||||
/// </summary>
|
||||
public string CompanyStatusDisplay => Company != null ? GetStatusMessage(Company) : string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the display text for the company's founded date
|
||||
/// </summary>
|
||||
public string CompanyFoundedDateDisplay => Company != null ? GetFoundedDateDisplay(Company) : string.Empty;
|
||||
|
||||
public IAsyncRelayCommand LoadData { get; }
|
||||
public ICommand GoBackCommand { get; }
|
||||
public IAsyncRelayCommand<CompanyDetailMachine> NavigateToMachineCommand { get; }
|
||||
public string Title { get; } = "Company Details";
|
||||
|
||||
partial void OnCompanyChanged(CompanyDto? oldValue, CompanyDto? newValue)
|
||||
{
|
||||
// Notify that computed properties have changed
|
||||
OnPropertyChanged(nameof(CompanyStatusDisplay));
|
||||
OnPropertyChanged(nameof(CompanyFoundedDateDisplay));
|
||||
}
|
||||
|
||||
partial void OnComputersFilterTextChanged(string value)
|
||||
{
|
||||
FilterComputers(value);
|
||||
}
|
||||
|
||||
partial void OnConsoelsFilterTextChanged(string value)
|
||||
{
|
||||
FilterConsoles(value);
|
||||
}
|
||||
|
||||
private void FilterComputers(string filterText)
|
||||
{
|
||||
ObservableCollection<CompanyDetailMachine> filtered = string.IsNullOrWhiteSpace(filterText)
|
||||
? new ObservableCollection<
|
||||
CompanyDetailMachine>(Computers)
|
||||
: new
|
||||
ObservableCollection<
|
||||
CompanyDetailMachine>(Computers.Where(c =>
|
||||
c.Name.Contains(filterText,
|
||||
StringComparison
|
||||
.OrdinalIgnoreCase)));
|
||||
|
||||
FilteredComputers = filtered;
|
||||
}
|
||||
|
||||
private void FilterConsoles(string filterText)
|
||||
{
|
||||
ObservableCollection<CompanyDetailMachine> filtered = string.IsNullOrWhiteSpace(filterText)
|
||||
? new ObservableCollection<
|
||||
CompanyDetailMachine>(Consoles)
|
||||
: new
|
||||
ObservableCollection<
|
||||
CompanyDetailMachine>(Consoles.Where(c =>
|
||||
c.Name.Contains(filterText,
|
||||
StringComparison
|
||||
.OrdinalIgnoreCase)));
|
||||
|
||||
FilteredConsoles = filtered;
|
||||
}
|
||||
|
||||
private async Task NavigateToMachineAsync(CompanyDetailMachine? machine)
|
||||
{
|
||||
if(machine == null) return;
|
||||
|
||||
var navParam = new MachineViewNavigationParameter
|
||||
{
|
||||
MachineId = machine.Id,
|
||||
NavigationSource = this
|
||||
};
|
||||
|
||||
await _navigator.NavigateViewModelAsync<MachineViewViewModel>(this, data: navParam);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the formatted founding date with unknown handling
|
||||
/// </summary>
|
||||
public string GetFoundedDateDisplay(CompanyDto company)
|
||||
{
|
||||
if(company.Founded is null) return string.Empty;
|
||||
|
||||
DateTime date = company.Founded.Value.DateTime;
|
||||
|
||||
if(company.FoundedMonthIsUnknown ?? false) return $"{date.Year}.";
|
||||
|
||||
if(company.FoundedDayIsUnknown ?? false) return $"{date:Y}.";
|
||||
|
||||
return $"{date:D}.";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the formatted sold/event date with unknown handling
|
||||
/// </summary>
|
||||
public string GetEventDateDisplay(CompanyDto? company, bool monthUnknown = false, bool dayUnknown = false)
|
||||
{
|
||||
if(company?.Sold is null) return _localizer["unknown date"].Value;
|
||||
|
||||
DateTime date = company.Sold.Value.DateTime;
|
||||
|
||||
if(monthUnknown || (company.SoldMonthIsUnknown ?? false)) return $"{date.Year}";
|
||||
|
||||
if(dayUnknown || (company.SoldDayIsUnknown ?? false)) return $"{date:Y}";
|
||||
|
||||
return $"{date:D}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the status message for the company
|
||||
/// </summary>
|
||||
public string GetStatusMessage(CompanyDto company)
|
||||
{
|
||||
return company.Status switch
|
||||
{
|
||||
1 => _localizer["Company is active."].Value,
|
||||
2 => GetSoldStatusMessage(company),
|
||||
3 => GetMergedStatusMessage(company),
|
||||
4 => GetBankruptcyMessage(company),
|
||||
5 => GetDefunctMessage(company),
|
||||
6 => GetRenamedStatusMessage(company),
|
||||
_ => _localizer["Current company status is unknown."].Value
|
||||
};
|
||||
}
|
||||
|
||||
private string GetSoldStatusMessage(CompanyDto company)
|
||||
{
|
||||
if(SoldToCompany != null)
|
||||
{
|
||||
return string.Format(_localizer["Company sold to {0} on {1}."].Value,
|
||||
SoldToCompany.Name,
|
||||
GetEventDateDisplay(company));
|
||||
}
|
||||
|
||||
if(company.Sold != null)
|
||||
{
|
||||
return string.Format(_localizer["Company sold on {0} to an unknown company."].Value,
|
||||
GetEventDateDisplay(company));
|
||||
}
|
||||
|
||||
return SoldToCompany != null
|
||||
? string.Format(_localizer["Company sold to {0} on an unknown date."].Value, SoldToCompany.Name)
|
||||
: _localizer["Company was sold to an unknown company on an unknown date."].Value;
|
||||
}
|
||||
|
||||
private string GetMergedStatusMessage(CompanyDto company)
|
||||
{
|
||||
if(SoldToCompany != null)
|
||||
{
|
||||
return string.Format(_localizer["Company merged on {0} to form {1}."].Value,
|
||||
GetEventDateDisplay(company),
|
||||
SoldToCompany.Name);
|
||||
}
|
||||
|
||||
if(company.Sold != null)
|
||||
{
|
||||
return string.Format(_localizer["Company merged on {0} to form an unknown company."].Value,
|
||||
GetEventDateDisplay(company));
|
||||
}
|
||||
|
||||
return SoldToCompany != null
|
||||
? string.Format(_localizer["Company merged on an unknown date to form {0}."].Value,
|
||||
SoldToCompany.Name)
|
||||
: _localizer["Company merged to form an unknown company on an unknown date."].Value;
|
||||
}
|
||||
|
||||
private string GetBankruptcyMessage(CompanyDto company) => company.Sold != null
|
||||
? string.Format(_localizer
|
||||
["Company declared bankruptcy on {0}."]
|
||||
.Value,
|
||||
GetEventDateDisplay(company))
|
||||
: _localizer
|
||||
["Company declared bankruptcy on an unknown date."]
|
||||
.Value;
|
||||
|
||||
private string GetDefunctMessage(CompanyDto company) => company.Sold != null
|
||||
? string.Format(_localizer
|
||||
["Company ceased operations on {0}."]
|
||||
.Value,
|
||||
GetEventDateDisplay(company))
|
||||
: _localizer
|
||||
["Company ceased operations on an unknown date."]
|
||||
.Value;
|
||||
|
||||
private string GetRenamedStatusMessage(CompanyDto company)
|
||||
{
|
||||
if(SoldToCompany != null)
|
||||
{
|
||||
return string.Format(_localizer["Company renamed to {0} on {1}."].Value,
|
||||
SoldToCompany.Name,
|
||||
GetEventDateDisplay(company));
|
||||
}
|
||||
|
||||
if(company.Sold != null)
|
||||
{
|
||||
return string.Format(_localizer["Company was renamed on {0} to an unknown name."].Value,
|
||||
GetEventDateDisplay(company));
|
||||
}
|
||||
|
||||
return SoldToCompany != null
|
||||
? string.Format(_localizer["Company renamed to {0} on an unknown date."].Value, SoldToCompany.Name)
|
||||
: _localizer["Company renamed to an unknown name on an unknown date."].Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads company details from the API
|
||||
/// </summary>
|
||||
private async Task LoadDataAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
IsLoading = true;
|
||||
ErrorMessage = string.Empty;
|
||||
HasError = false;
|
||||
IsDataLoaded = false;
|
||||
|
||||
if(CompanyId <= 0)
|
||||
{
|
||||
ErrorMessage = _localizer["Invalid company ID."].Value;
|
||||
HasError = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Load company details
|
||||
Company = await _companyDetailService.GetCompanyByIdAsync(CompanyId);
|
||||
|
||||
if(Company is null)
|
||||
{
|
||||
ErrorMessage = _localizer["Company not found."].Value;
|
||||
HasError = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Load sold-to company if applicable
|
||||
if(Company.SoldToId != null)
|
||||
{
|
||||
int soldToId = UntypedNodeExtractor.ExtractInt(Company.SoldToId);
|
||||
if(soldToId > 0) SoldToCompany = await _companyDetailService.GetSoldToCompanyAsync(soldToId);
|
||||
}
|
||||
|
||||
// Load computers and consoles made by this company
|
||||
List<MachineDto> machines = await _companyDetailService.GetComputersByCompanyAsync(CompanyId);
|
||||
Computers.Clear();
|
||||
Consoles.Clear();
|
||||
FilteredComputers.Clear();
|
||||
FilteredConsoles.Clear();
|
||||
|
||||
foreach(MachineDto machine in machines)
|
||||
{
|
||||
int machineId = UntypedNodeExtractor.ExtractInt(machine.Id);
|
||||
|
||||
var machineItem = new CompanyDetailMachine
|
||||
{
|
||||
Id = machineId,
|
||||
Name = machine.Name ?? string.Empty
|
||||
};
|
||||
|
||||
// Categorize by machine type enum
|
||||
if(machine.Type == (int)MachineType.Computer)
|
||||
Computers.Add(machineItem);
|
||||
else if(machine.Type == (int)MachineType.Console) Consoles.Add(machineItem);
|
||||
}
|
||||
|
||||
// Initialize filtered lists
|
||||
FilteredComputers = new ObservableCollection<CompanyDetailMachine>(Computers);
|
||||
FilteredConsoles = new ObservableCollection<CompanyDetailMachine>(Consoles);
|
||||
|
||||
IsDataLoaded = true;
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError("Error loading company details: {Exception}", ex.Message);
|
||||
ErrorMessage = _localizer["Failed to load company details. Please try again later."].Value;
|
||||
HasError = true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles back navigation
|
||||
/// </summary>
|
||||
private async Task GoBackAsync()
|
||||
{
|
||||
await _navigator.NavigateViewModelAsync<CompaniesViewModel>(this);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Data model for a machine in the company detail view
|
||||
/// </summary>
|
||||
public class CompanyDetailMachine
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; } = string.Empty;
|
||||
}
|
||||
251
Marechai.App/Presentation/ViewModels/ComputersListViewModel.cs
Normal file
251
Marechai.App/Presentation/ViewModels/ComputersListViewModel.cs
Normal file
@@ -0,0 +1,251 @@
|
||||
#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.Helpers;
|
||||
using Marechai.App.Presentation.Models;
|
||||
using Marechai.App.Services;
|
||||
using Uno.Extensions.Navigation;
|
||||
|
||||
namespace Marechai.App.Presentation.ViewModels;
|
||||
|
||||
/// <summary>
|
||||
/// ViewModel for displaying a filtered list of computers
|
||||
/// </summary>
|
||||
public partial class ComputersListViewModel : ObservableObject
|
||||
{
|
||||
private readonly ComputersService _computersService;
|
||||
private readonly IComputersListFilterContext _filterContext;
|
||||
private readonly IStringLocalizer _localizer;
|
||||
private readonly ILogger<ComputersListViewModel> _logger;
|
||||
private readonly INavigator _navigator;
|
||||
|
||||
[ObservableProperty]
|
||||
private ObservableCollection<ComputerListItem> _computersList = [];
|
||||
|
||||
[ObservableProperty]
|
||||
private string _errorMessage = string.Empty;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _filterDescription = string.Empty;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _hasError;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _isDataLoaded;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _isLoading;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _pageTitle = string.Empty;
|
||||
|
||||
public ComputersListViewModel(ComputersService computersService, IStringLocalizer localizer,
|
||||
ILogger<ComputersListViewModel> logger, INavigator navigator,
|
||||
IComputersListFilterContext filterContext)
|
||||
{
|
||||
_computersService = computersService;
|
||||
_localizer = localizer;
|
||||
_logger = logger;
|
||||
_navigator = navigator;
|
||||
_filterContext = filterContext;
|
||||
LoadData = new AsyncRelayCommand(LoadDataAsync);
|
||||
GoBackCommand = new AsyncRelayCommand(GoBackAsync);
|
||||
NavigateToComputerCommand = new AsyncRelayCommand<ComputerListItem>(NavigateToComputerAsync);
|
||||
}
|
||||
|
||||
public IAsyncRelayCommand LoadData { get; }
|
||||
public ICommand GoBackCommand { get; }
|
||||
public IAsyncRelayCommand<ComputerListItem> NavigateToComputerCommand { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the filter type
|
||||
/// </summary>
|
||||
public ComputerListFilterType FilterType
|
||||
{
|
||||
get => _filterContext.FilterType;
|
||||
set => _filterContext.FilterType = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the filter value
|
||||
/// </summary>
|
||||
public string FilterValue
|
||||
{
|
||||
get => _filterContext.FilterValue;
|
||||
set => _filterContext.FilterValue = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads computers based on the current filter
|
||||
/// </summary>
|
||||
private async Task LoadDataAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
IsLoading = true;
|
||||
ErrorMessage = string.Empty;
|
||||
HasError = false;
|
||||
IsDataLoaded = false;
|
||||
ComputersList.Clear();
|
||||
|
||||
_logger.LogInformation("LoadDataAsync called. FilterType={FilterType}, FilterValue={FilterValue}",
|
||||
FilterType,
|
||||
FilterValue);
|
||||
|
||||
// Update title and filter description based on filter type
|
||||
UpdateFilterDescription();
|
||||
|
||||
// Load computers from the API based on the current filter
|
||||
await LoadComputersFromApiAsync();
|
||||
|
||||
_logger.LogInformation("LoadComputersFromApiAsync completed. ComputersList.Count={Count}",
|
||||
ComputersList.Count);
|
||||
|
||||
if(ComputersList.Count == 0)
|
||||
{
|
||||
ErrorMessage = _localizer["No computers found for this filter"].Value;
|
||||
HasError = true;
|
||||
|
||||
_logger.LogWarning("No computers found for filter: {FilterType} {FilterValue}",
|
||||
FilterType,
|
||||
FilterValue);
|
||||
}
|
||||
else
|
||||
IsDataLoaded = true;
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error loading computers: {Exception}", ex.Message);
|
||||
ErrorMessage = _localizer["Failed to load computers. Please try again later."].Value;
|
||||
HasError = true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the title and filter description based on the current filter
|
||||
/// </summary>
|
||||
private void UpdateFilterDescription()
|
||||
{
|
||||
switch(FilterType)
|
||||
{
|
||||
case ComputerListFilterType.All:
|
||||
PageTitle = _localizer["All Computers"];
|
||||
FilterDescription = _localizer["Browsing all computers in the database"];
|
||||
|
||||
break;
|
||||
|
||||
case ComputerListFilterType.Letter:
|
||||
if(!string.IsNullOrEmpty(FilterValue) && FilterValue.Length == 1)
|
||||
{
|
||||
PageTitle = $"{_localizer["Computers Starting with"]} {FilterValue}";
|
||||
FilterDescription = $"{_localizer["Showing computers that start with"]} {FilterValue}";
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case ComputerListFilterType.Year:
|
||||
if(!string.IsNullOrEmpty(FilterValue) && int.TryParse(FilterValue, out int year))
|
||||
{
|
||||
PageTitle = $"{_localizer["Computers from"]} {year}";
|
||||
FilterDescription = $"{_localizer["Showing computers released in"]} {year}";
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads computers from the API based on the current filter
|
||||
/// </summary>
|
||||
private async Task LoadComputersFromApiAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
List<MachineDto> computers = FilterType switch
|
||||
{
|
||||
ComputerListFilterType.Letter when FilterValue.Length == 1 =>
|
||||
await _computersService.GetComputersByLetterAsync(FilterValue[0]),
|
||||
|
||||
ComputerListFilterType.Year when int.TryParse(FilterValue, out int year) =>
|
||||
await _computersService.GetComputersByYearAsync(year),
|
||||
|
||||
_ => await _computersService.GetAllComputersAsync()
|
||||
};
|
||||
|
||||
// Add computers to the list sorted by name
|
||||
foreach(MachineDto computer in computers.OrderBy(c => c.Name))
|
||||
{
|
||||
int year = computer.Introduced?.Year ?? 0;
|
||||
int id = UntypedNodeExtractor.ExtractInt(computer.Id);
|
||||
|
||||
_logger.LogInformation("Computer: {Name}, Introduced: {Introduced}, Year: {Year}, Company: {Company}, ID: {Id}",
|
||||
computer.Name,
|
||||
computer.Introduced,
|
||||
year,
|
||||
computer.Company,
|
||||
id);
|
||||
|
||||
ComputersList.Add(new ComputerListItem
|
||||
{
|
||||
Id = id,
|
||||
Name = computer.Name ?? string.Empty,
|
||||
Year = year,
|
||||
Manufacturer = computer.Company ?? string.Empty
|
||||
});
|
||||
}
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error loading computers from API");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Navigates back to the computers main view
|
||||
/// </summary>
|
||||
private async Task GoBackAsync()
|
||||
{
|
||||
await _navigator.NavigateViewModelAsync<ComputersViewModel>(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Navigates to the computer detail view
|
||||
/// </summary>
|
||||
private async Task NavigateToComputerAsync(ComputerListItem? computer)
|
||||
{
|
||||
if(computer is null) return;
|
||||
|
||||
_logger.LogInformation("Navigating to computer detail: {ComputerName} (ID: {ComputerId})",
|
||||
computer.Name,
|
||||
computer.Id);
|
||||
|
||||
var navParam = new MachineViewNavigationParameter
|
||||
{
|
||||
MachineId = computer.Id,
|
||||
NavigationSource = this
|
||||
};
|
||||
|
||||
await _navigator.NavigateViewModelAsync<MachineViewViewModel>(this, data: navParam);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Data model for a computer in the list
|
||||
/// </summary>
|
||||
public class ComputerListItem
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public int Year { get; set; }
|
||||
public string Manufacturer { get; set; } = string.Empty;
|
||||
}
|
||||
207
Marechai.App/Presentation/ViewModels/ComputersViewModel.cs
Normal file
207
Marechai.App/Presentation/ViewModels/ComputersViewModel.cs
Normal file
@@ -0,0 +1,207 @@
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using Marechai.App.Services;
|
||||
using Uno.Extensions.Navigation;
|
||||
|
||||
namespace Marechai.App.Presentation.ViewModels;
|
||||
|
||||
public partial class ComputersViewModel : ObservableObject
|
||||
{
|
||||
private readonly ComputersService _computersService;
|
||||
private readonly IComputersListFilterContext _filterContext;
|
||||
private readonly IStringLocalizer _localizer;
|
||||
private readonly ILogger<ComputersViewModel> _logger;
|
||||
private readonly INavigator _navigator;
|
||||
|
||||
[ObservableProperty]
|
||||
private int _computerCount;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _computerCountText = string.Empty;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _errorMessage = string.Empty;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _hasError;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _isDataLoaded;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _isLoading;
|
||||
|
||||
[ObservableProperty]
|
||||
private ObservableCollection<char> _lettersList = [];
|
||||
|
||||
[ObservableProperty]
|
||||
private int _maximumYear;
|
||||
|
||||
[ObservableProperty]
|
||||
private int _minimumYear;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _yearsGridTitle = string.Empty;
|
||||
|
||||
[ObservableProperty]
|
||||
private ObservableCollection<int> _yearsList = [];
|
||||
|
||||
public ComputersViewModel(ComputersService computersService, IStringLocalizer localizer,
|
||||
ILogger<ComputersViewModel> logger, INavigator navigator,
|
||||
IComputersListFilterContext filterContext)
|
||||
{
|
||||
_computersService = computersService;
|
||||
_localizer = localizer;
|
||||
_logger = logger;
|
||||
_navigator = navigator;
|
||||
_filterContext = filterContext;
|
||||
LoadData = new AsyncRelayCommand(LoadDataAsync);
|
||||
GoBackCommand = new AsyncRelayCommand(GoBackAsync);
|
||||
NavigateByLetterCommand = new AsyncRelayCommand<char>(NavigateByLetterAsync);
|
||||
NavigateByYearCommand = new AsyncRelayCommand<int>(NavigateByYearAsync);
|
||||
NavigateAllComputersCommand = new AsyncRelayCommand(NavigateAllComputersAsync);
|
||||
|
||||
InitializeLetters();
|
||||
}
|
||||
|
||||
public IAsyncRelayCommand LoadData { get; }
|
||||
public ICommand GoBackCommand { get; }
|
||||
public IAsyncRelayCommand<char> NavigateByLetterCommand { get; }
|
||||
public IAsyncRelayCommand<int> NavigateByYearCommand { get; }
|
||||
public IAsyncRelayCommand NavigateAllComputersCommand { get; }
|
||||
public string Title { get; } = "Computers";
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the alphabet list (A-Z)
|
||||
/// </summary>
|
||||
private void InitializeLetters()
|
||||
{
|
||||
LettersList.Clear();
|
||||
|
||||
for(var c = 'A'; c <= 'Z'; c++) LettersList.Add(c);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads computers count, minimum and maximum years from the API
|
||||
/// </summary>
|
||||
private async Task LoadDataAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
IsLoading = true;
|
||||
ErrorMessage = string.Empty;
|
||||
HasError = false;
|
||||
IsDataLoaded = false;
|
||||
YearsList.Clear();
|
||||
|
||||
// Load all data in parallel for better performance
|
||||
Task<int> countTask = _computersService.GetComputersCountAsync();
|
||||
Task<int> minYearTask = _computersService.GetMinimumYearAsync();
|
||||
Task<int> maxYearTask = _computersService.GetMaximumYearAsync();
|
||||
await Task.WhenAll(countTask, minYearTask, maxYearTask);
|
||||
|
||||
ComputerCount = countTask.Result;
|
||||
MinimumYear = minYearTask.Result;
|
||||
MaximumYear = maxYearTask.Result;
|
||||
|
||||
// Update display text
|
||||
ComputerCountText = _localizer["Computers in the database"];
|
||||
|
||||
// Generate years list
|
||||
if(MinimumYear > 0 && MaximumYear > 0)
|
||||
{
|
||||
for(int year = MinimumYear; year <= MaximumYear; year++) YearsList.Add(year);
|
||||
|
||||
YearsGridTitle = $"Browse by Year ({MinimumYear} - {MaximumYear})";
|
||||
}
|
||||
|
||||
if(ComputerCount == 0)
|
||||
{
|
||||
ErrorMessage = _localizer["No computers found"].Value;
|
||||
HasError = true;
|
||||
}
|
||||
else
|
||||
IsDataLoaded = true;
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError("Error loading computers data: {Exception}", ex.Message);
|
||||
ErrorMessage = _localizer["Failed to load computers data. Please try again later."].Value;
|
||||
HasError = true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles back navigation
|
||||
/// </summary>
|
||||
private async Task GoBackAsync()
|
||||
{
|
||||
await _navigator.NavigateViewModelAsync<MainViewModel>(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Navigates to computers filtered by letter
|
||||
/// </summary>
|
||||
private async Task NavigateByLetterAsync(char letter)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("Navigating to computers by letter: {Letter}", letter);
|
||||
_filterContext.FilterType = ComputerListFilterType.Letter;
|
||||
_filterContext.FilterValue = letter.ToString();
|
||||
await _navigator.NavigateRouteAsync(this, "list-computers");
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError("Error navigating to letter computers: {Exception}", ex.Message);
|
||||
ErrorMessage = _localizer["Failed to navigate. Please try again."].Value;
|
||||
HasError = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Navigates to computers filtered by year
|
||||
/// </summary>
|
||||
private async Task NavigateByYearAsync(int year)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("Navigating to computers by year: {Year}", year);
|
||||
_filterContext.FilterType = ComputerListFilterType.Year;
|
||||
_filterContext.FilterValue = year.ToString();
|
||||
await _navigator.NavigateRouteAsync(this, "list-computers");
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError("Error navigating to year computers: {Exception}", ex.Message);
|
||||
ErrorMessage = _localizer["Failed to navigate. Please try again."].Value;
|
||||
HasError = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Navigates to all computers view
|
||||
/// </summary>
|
||||
private async Task NavigateAllComputersAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("Navigating to all computers");
|
||||
_filterContext.FilterType = ComputerListFilterType.All;
|
||||
_filterContext.FilterValue = string.Empty;
|
||||
await _navigator.NavigateRouteAsync(this, "list-computers");
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError("Error navigating to all computers: {Exception}", ex.Message);
|
||||
ErrorMessage = _localizer["Failed to navigate. Please try again."].Value;
|
||||
HasError = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
249
Marechai.App/Presentation/ViewModels/ConsolesListViewModel.cs
Normal file
249
Marechai.App/Presentation/ViewModels/ConsolesListViewModel.cs
Normal file
@@ -0,0 +1,249 @@
|
||||
#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.Helpers;
|
||||
using Marechai.App.Presentation.Models;
|
||||
using Marechai.App.Services;
|
||||
using Uno.Extensions.Navigation;
|
||||
|
||||
namespace Marechai.App.Presentation.ViewModels;
|
||||
|
||||
/// <summary>
|
||||
/// ViewModel for displaying a filtered list of consoles
|
||||
/// </summary>
|
||||
public partial class ConsolesListViewModel : ObservableObject
|
||||
{
|
||||
private readonly ConsolesService _consolesService;
|
||||
private readonly IConsolesListFilterContext _filterContext;
|
||||
private readonly IStringLocalizer _localizer;
|
||||
private readonly ILogger<ConsolesListViewModel> _logger;
|
||||
private readonly INavigator _navigator;
|
||||
|
||||
[ObservableProperty]
|
||||
private ObservableCollection<ConsoleListItem> _consolesList = [];
|
||||
|
||||
[ObservableProperty]
|
||||
private string _errorMessage = string.Empty;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _filterDescription = string.Empty;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _hasError;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _isDataLoaded;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _isLoading;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _pageTitle = string.Empty;
|
||||
|
||||
public ConsolesListViewModel(ConsolesService consolesService, IStringLocalizer localizer,
|
||||
ILogger<ConsolesListViewModel> logger, INavigator navigator,
|
||||
IConsolesListFilterContext filterContext)
|
||||
{
|
||||
_consolesService = consolesService;
|
||||
_localizer = localizer;
|
||||
_logger = logger;
|
||||
_navigator = navigator;
|
||||
_filterContext = filterContext;
|
||||
LoadData = new AsyncRelayCommand(LoadDataAsync);
|
||||
GoBackCommand = new AsyncRelayCommand(GoBackAsync);
|
||||
NavigateToConsoleCommand = new AsyncRelayCommand<ConsoleListItem>(NavigateToConsoleAsync);
|
||||
}
|
||||
|
||||
public IAsyncRelayCommand LoadData { get; }
|
||||
public ICommand GoBackCommand { get; }
|
||||
public IAsyncRelayCommand<ConsoleListItem> NavigateToConsoleCommand { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the filter type
|
||||
/// </summary>
|
||||
public ConsoleListFilterType FilterType
|
||||
{
|
||||
get => _filterContext.FilterType;
|
||||
set => _filterContext.FilterType = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the filter value
|
||||
/// </summary>
|
||||
public string FilterValue
|
||||
{
|
||||
get => _filterContext.FilterValue;
|
||||
set => _filterContext.FilterValue = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads consoles based on the current filter
|
||||
/// </summary>
|
||||
private async Task LoadDataAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
IsLoading = true;
|
||||
ErrorMessage = string.Empty;
|
||||
HasError = false;
|
||||
IsDataLoaded = false;
|
||||
ConsolesList.Clear();
|
||||
|
||||
_logger.LogInformation("LoadDataAsync called. FilterType={FilterType}, FilterValue={FilterValue}",
|
||||
FilterType,
|
||||
FilterValue);
|
||||
|
||||
// Update title and filter description based on filter type
|
||||
UpdateFilterDescription();
|
||||
|
||||
// Load consoles from the API based on the current filter
|
||||
await LoadConsolesFromApiAsync();
|
||||
|
||||
_logger.LogInformation("LoadConsolesFromApiAsync completed. ConsolesList.Count={Count}",
|
||||
ConsolesList.Count);
|
||||
|
||||
if(ConsolesList.Count == 0)
|
||||
{
|
||||
ErrorMessage = _localizer["No consoles found for this filter"].Value;
|
||||
HasError = true;
|
||||
|
||||
_logger.LogWarning("No consoles found for filter: {FilterType} {FilterValue}", FilterType, FilterValue);
|
||||
}
|
||||
else
|
||||
IsDataLoaded = true;
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error loading consoles: {Exception}", ex.Message);
|
||||
ErrorMessage = _localizer["Failed to load consoles. Please try again later."].Value;
|
||||
HasError = true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the title and filter description based on the current filter
|
||||
/// </summary>
|
||||
private void UpdateFilterDescription()
|
||||
{
|
||||
switch(FilterType)
|
||||
{
|
||||
case ConsoleListFilterType.All:
|
||||
PageTitle = _localizer["All Consoles"];
|
||||
FilterDescription = _localizer["Browsing all consoles in the database"];
|
||||
|
||||
break;
|
||||
|
||||
case ConsoleListFilterType.Letter:
|
||||
if(!string.IsNullOrEmpty(FilterValue) && FilterValue.Length == 1)
|
||||
{
|
||||
PageTitle = $"{_localizer["Consoles Starting with"]} {FilterValue}";
|
||||
FilterDescription = $"{_localizer["Showing consoles that start with"]} {FilterValue}";
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case ConsoleListFilterType.Year:
|
||||
if(!string.IsNullOrEmpty(FilterValue) && int.TryParse(FilterValue, out int year))
|
||||
{
|
||||
PageTitle = $"{_localizer["Consoles from"]} {year}";
|
||||
FilterDescription = $"{_localizer["Showing consoles released in"]} {year}";
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads consoles from the API based on the current filter
|
||||
/// </summary>
|
||||
private async Task LoadConsolesFromApiAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
List<MachineDto> consoles = FilterType switch
|
||||
{
|
||||
ConsoleListFilterType.Letter when FilterValue.Length == 1 =>
|
||||
await _consolesService.GetConsolesByLetterAsync(FilterValue[0]),
|
||||
|
||||
ConsoleListFilterType.Year when int.TryParse(FilterValue, out int year) =>
|
||||
await _consolesService.GetConsolesByYearAsync(year),
|
||||
|
||||
_ => await _consolesService.GetAllConsolesAsync()
|
||||
};
|
||||
|
||||
// Add consoles to the list sorted by name
|
||||
foreach(MachineDto console in consoles.OrderBy(c => c.Name))
|
||||
{
|
||||
int year = console.Introduced?.Year ?? 0;
|
||||
int id = UntypedNodeExtractor.ExtractInt(console.Id);
|
||||
|
||||
_logger.LogInformation("Console: {Name}, Introduced: {Introduced}, Year: {Year}, Company: {Company}, ID: {Id}",
|
||||
console.Name,
|
||||
console.Introduced,
|
||||
year,
|
||||
console.Company,
|
||||
id);
|
||||
|
||||
ConsolesList.Add(new ConsoleListItem
|
||||
{
|
||||
Id = id,
|
||||
Name = console.Name ?? string.Empty,
|
||||
Year = year,
|
||||
Manufacturer = console.Company ?? string.Empty
|
||||
});
|
||||
}
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error loading consoles from API");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Navigates back to the consoles main view
|
||||
/// </summary>
|
||||
private async Task GoBackAsync()
|
||||
{
|
||||
await _navigator.NavigateViewModelAsync<ConsolesViewModel>(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Navigates to the console detail view
|
||||
/// </summary>
|
||||
private async Task NavigateToConsoleAsync(ConsoleListItem? console)
|
||||
{
|
||||
if(console is null) return;
|
||||
|
||||
_logger.LogInformation("Navigating to console detail: {ConsoleName} (ID: {ConsoleId})",
|
||||
console.Name,
|
||||
console.Id);
|
||||
|
||||
var navParam = new MachineViewNavigationParameter
|
||||
{
|
||||
MachineId = console.Id,
|
||||
NavigationSource = this
|
||||
};
|
||||
|
||||
await _navigator.NavigateViewModelAsync<MachineViewViewModel>(this, data: navParam);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Data model for a console in the list
|
||||
/// </summary>
|
||||
public class ConsoleListItem
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public int Year { get; set; }
|
||||
public string Manufacturer { get; set; } = string.Empty;
|
||||
}
|
||||
207
Marechai.App/Presentation/ViewModels/ConsolesViewModel.cs
Normal file
207
Marechai.App/Presentation/ViewModels/ConsolesViewModel.cs
Normal file
@@ -0,0 +1,207 @@
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using Marechai.App.Services;
|
||||
using Uno.Extensions.Navigation;
|
||||
|
||||
namespace Marechai.App.Presentation.ViewModels;
|
||||
|
||||
public partial class ConsolesViewModel : ObservableObject
|
||||
{
|
||||
private readonly ConsolesService _consolesService;
|
||||
private readonly IConsolesListFilterContext _filterContext;
|
||||
private readonly IStringLocalizer _localizer;
|
||||
private readonly ILogger<ConsolesViewModel> _logger;
|
||||
private readonly INavigator _navigator;
|
||||
|
||||
[ObservableProperty]
|
||||
private int _consoleCount;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _consoleCountText = string.Empty;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _errorMessage = string.Empty;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _hasError;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _isDataLoaded;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _isLoading;
|
||||
|
||||
[ObservableProperty]
|
||||
private ObservableCollection<char> _lettersList = [];
|
||||
|
||||
[ObservableProperty]
|
||||
private int _maximumYear;
|
||||
|
||||
[ObservableProperty]
|
||||
private int _minimumYear;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _yearsGridTitle = string.Empty;
|
||||
|
||||
[ObservableProperty]
|
||||
private ObservableCollection<int> _yearsList = [];
|
||||
|
||||
public ConsolesViewModel(ConsolesService consolesService, IStringLocalizer localizer,
|
||||
ILogger<ConsolesViewModel> logger, INavigator navigator,
|
||||
IConsolesListFilterContext filterContext)
|
||||
{
|
||||
_consolesService = consolesService;
|
||||
_localizer = localizer;
|
||||
_logger = logger;
|
||||
_navigator = navigator;
|
||||
_filterContext = filterContext;
|
||||
LoadData = new AsyncRelayCommand(LoadDataAsync);
|
||||
GoBackCommand = new AsyncRelayCommand(GoBackAsync);
|
||||
NavigateByLetterCommand = new AsyncRelayCommand<char>(NavigateByLetterAsync);
|
||||
NavigateByYearCommand = new AsyncRelayCommand<int>(NavigateByYearAsync);
|
||||
NavigateAllConsolesCommand = new AsyncRelayCommand(NavigateAllConsolesAsync);
|
||||
|
||||
InitializeLetters();
|
||||
}
|
||||
|
||||
public IAsyncRelayCommand LoadData { get; }
|
||||
public ICommand GoBackCommand { get; }
|
||||
public IAsyncRelayCommand<char> NavigateByLetterCommand { get; }
|
||||
public IAsyncRelayCommand<int> NavigateByYearCommand { get; }
|
||||
public IAsyncRelayCommand NavigateAllConsolesCommand { get; }
|
||||
public string Title { get; } = "Consoles";
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the alphabet list (A-Z)
|
||||
/// </summary>
|
||||
private void InitializeLetters()
|
||||
{
|
||||
LettersList.Clear();
|
||||
|
||||
for(var c = 'A'; c <= 'Z'; c++) LettersList.Add(c);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads consoles count, minimum and maximum years from the API
|
||||
/// </summary>
|
||||
private async Task LoadDataAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
IsLoading = true;
|
||||
ErrorMessage = string.Empty;
|
||||
HasError = false;
|
||||
IsDataLoaded = false;
|
||||
YearsList.Clear();
|
||||
|
||||
// Load all data in parallel for better performance
|
||||
Task<int> countTask = _consolesService.GetConsolesCountAsync();
|
||||
Task<int> minYearTask = _consolesService.GetMinimumYearAsync();
|
||||
Task<int> maxYearTask = _consolesService.GetMaximumYearAsync();
|
||||
await Task.WhenAll(countTask, minYearTask, maxYearTask);
|
||||
|
||||
ConsoleCount = countTask.Result;
|
||||
MinimumYear = minYearTask.Result;
|
||||
MaximumYear = maxYearTask.Result;
|
||||
|
||||
// Update display text
|
||||
ConsoleCountText = _localizer["Consoles in the database"];
|
||||
|
||||
// Generate years list
|
||||
if(MinimumYear > 0 && MaximumYear > 0)
|
||||
{
|
||||
for(int year = MinimumYear; year <= MaximumYear; year++) YearsList.Add(year);
|
||||
|
||||
YearsGridTitle = $"Browse by Year ({MinimumYear} - {MaximumYear})";
|
||||
}
|
||||
|
||||
if(ConsoleCount == 0)
|
||||
{
|
||||
ErrorMessage = _localizer["No consoles found"].Value;
|
||||
HasError = true;
|
||||
}
|
||||
else
|
||||
IsDataLoaded = true;
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError("Error loading consoles data: {Exception}", ex.Message);
|
||||
ErrorMessage = _localizer["Failed to load consoles data. Please try again later."].Value;
|
||||
HasError = true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles back navigation
|
||||
/// </summary>
|
||||
private async Task GoBackAsync()
|
||||
{
|
||||
await _navigator.NavigateViewModelAsync<MainViewModel>(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Navigates to consoles filtered by letter
|
||||
/// </summary>
|
||||
private async Task NavigateByLetterAsync(char letter)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("Navigating to consoles by letter: {Letter}", letter);
|
||||
_filterContext.FilterType = ConsoleListFilterType.Letter;
|
||||
_filterContext.FilterValue = letter.ToString();
|
||||
await _navigator.NavigateRouteAsync(this, "list-consoles");
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError("Error navigating to letter consoles: {Exception}", ex.Message);
|
||||
ErrorMessage = _localizer["Failed to navigate. Please try again."].Value;
|
||||
HasError = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Navigates to consoles filtered by year
|
||||
/// </summary>
|
||||
private async Task NavigateByYearAsync(int year)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("Navigating to consoles by year: {Year}", year);
|
||||
_filterContext.FilterType = ConsoleListFilterType.Year;
|
||||
_filterContext.FilterValue = year.ToString();
|
||||
await _navigator.NavigateRouteAsync(this, "list-consoles");
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError("Error navigating to year consoles: {Exception}", ex.Message);
|
||||
ErrorMessage = _localizer["Failed to navigate. Please try again."].Value;
|
||||
HasError = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Navigates to all consoles view
|
||||
/// </summary>
|
||||
private async Task NavigateAllConsolesAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("Navigating to all consoles");
|
||||
_filterContext.FilterType = ConsoleListFilterType.All;
|
||||
_filterContext.FilterValue = string.Empty;
|
||||
await _navigator.NavigateRouteAsync(this, "list-consoles");
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError("Error navigating to all consoles: {Exception}", ex.Message);
|
||||
ErrorMessage = _localizer["Failed to navigate. Please try again."].Value;
|
||||
HasError = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
407
Marechai.App/Presentation/ViewModels/MachineViewViewModel.cs
Normal file
407
Marechai.App/Presentation/ViewModels/MachineViewViewModel.cs
Normal file
@@ -0,0 +1,407 @@
|
||||
/******************************************************************************
|
||||
// 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
|
||||
*******************************************************************************/
|
||||
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Threading.Tasks;
|
||||
using Humanizer;
|
||||
using Marechai.App.Helpers;
|
||||
using Marechai.App.Presentation.Models;
|
||||
using Marechai.App.Services;
|
||||
using Marechai.Data;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Uno.Extensions.Navigation;
|
||||
|
||||
namespace Marechai.App.Presentation.ViewModels;
|
||||
|
||||
public partial class MachineViewViewModel : ObservableObject
|
||||
{
|
||||
private readonly ComputersService _computersService;
|
||||
private readonly ILogger<MachineViewViewModel> _logger;
|
||||
private readonly INavigator _navigator;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _companyName = string.Empty;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _errorMessage = string.Empty;
|
||||
|
||||
[ObservableProperty]
|
||||
private string? _familyName;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _hasError;
|
||||
|
||||
[ObservableProperty]
|
||||
private string? _introductionDateDisplay;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _isDataLoaded;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _isLoading;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _isPrototype;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _machineName = string.Empty;
|
||||
|
||||
[ObservableProperty]
|
||||
private string? _modelName;
|
||||
private object? _navigationSource;
|
||||
|
||||
[ObservableProperty]
|
||||
private Visibility _showFamily = Visibility.Collapsed;
|
||||
|
||||
[ObservableProperty]
|
||||
private Visibility _showFamilyOrModel = Visibility.Collapsed;
|
||||
|
||||
[ObservableProperty]
|
||||
private Visibility _showGpus = Visibility.Collapsed;
|
||||
|
||||
[ObservableProperty]
|
||||
private Visibility _showIntroductionDate = Visibility.Collapsed;
|
||||
|
||||
[ObservableProperty]
|
||||
private Visibility _showMemory = Visibility.Collapsed;
|
||||
|
||||
[ObservableProperty]
|
||||
private Visibility _showModel = Visibility.Collapsed;
|
||||
|
||||
[ObservableProperty]
|
||||
private Visibility _showProcessors = Visibility.Collapsed;
|
||||
|
||||
[ObservableProperty]
|
||||
private Visibility _showSoundSynthesizers = Visibility.Collapsed;
|
||||
|
||||
[ObservableProperty]
|
||||
private Visibility _showStorage = Visibility.Collapsed;
|
||||
|
||||
public MachineViewViewModel(ILogger<MachineViewViewModel> logger, INavigator navigator,
|
||||
ComputersService computersService)
|
||||
{
|
||||
_logger = logger;
|
||||
_navigator = navigator;
|
||||
_computersService = computersService;
|
||||
}
|
||||
|
||||
public ObservableCollection<ProcessorDisplayItem> Processors { get; } = [];
|
||||
public ObservableCollection<MemoryDisplayItem> Memory { get; } = [];
|
||||
public ObservableCollection<GpuDisplayItem> Gpus { get; } = [];
|
||||
public ObservableCollection<SoundSynthesizerDisplayItem> SoundSynthesizers { get; } = [];
|
||||
public ObservableCollection<StorageDisplayItem> Storage { get; } = [];
|
||||
|
||||
[RelayCommand]
|
||||
public async Task GoBack()
|
||||
{
|
||||
// If we came from News, navigate back to News
|
||||
if(_navigationSource is NewsViewModel)
|
||||
{
|
||||
await _navigator.NavigateViewModelAsync<NewsViewModel>(this);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// If we came from CompanyDetailViewModel, navigate back to company details
|
||||
if(_navigationSource is CompanyDetailViewModel companyVm)
|
||||
{
|
||||
var navParam = new CompanyDetailNavigationParameter
|
||||
{
|
||||
CompanyId = companyVm.CompanyId
|
||||
};
|
||||
|
||||
await _navigator.NavigateViewModelAsync<CompanyDetailViewModel>(this, data: navParam);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// If we came from ConsolesListViewModel, navigate back to consoles list
|
||||
if(_navigationSource is ConsolesListViewModel)
|
||||
{
|
||||
await _navigator.NavigateViewModelAsync<ConsolesListViewModel>(this);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// If we came from ComputersListViewModel, navigate back to computers list
|
||||
if(_navigationSource is ComputersListViewModel)
|
||||
{
|
||||
await _navigator.NavigateViewModelAsync<ComputersListViewModel>(this);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, try to go back in the navigation stack
|
||||
await _navigator.GoBack(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the navigation source (where we came from).
|
||||
/// </summary>
|
||||
public void SetNavigationSource(object? source)
|
||||
{
|
||||
_navigationSource = source;
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
public Task LoadData()
|
||||
{
|
||||
// Placeholder for retry functionality
|
||||
HasError = false;
|
||||
ErrorMessage = string.Empty;
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public async Task LoadMachineAsync(int machineId)
|
||||
{
|
||||
try
|
||||
{
|
||||
IsLoading = true;
|
||||
IsDataLoaded = false;
|
||||
HasError = false;
|
||||
ErrorMessage = string.Empty;
|
||||
Processors.Clear();
|
||||
Memory.Clear();
|
||||
Gpus.Clear();
|
||||
SoundSynthesizers.Clear();
|
||||
Storage.Clear();
|
||||
|
||||
_logger.LogInformation("Loading machine {MachineId}", machineId);
|
||||
|
||||
// Fetch machine data from API
|
||||
MachineDto? machine = await _computersService.GetMachineByIdAsync(machineId);
|
||||
|
||||
if(machine is null)
|
||||
{
|
||||
HasError = true;
|
||||
ErrorMessage = "Machine not found";
|
||||
IsLoading = false;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Populate basic information
|
||||
MachineName = machine.Name ?? string.Empty;
|
||||
CompanyName = machine.Company ?? string.Empty;
|
||||
FamilyName = machine.FamilyName;
|
||||
ModelName = machine.Model;
|
||||
|
||||
// Check if this is a prototype (year 1000 is used as placeholder for prototypes)
|
||||
IsPrototype = machine.Introduced?.Year == 1000;
|
||||
|
||||
// Set introduction date if available and not a prototype
|
||||
if(machine.Introduced.HasValue && machine.Introduced.Value.Year != 1000)
|
||||
IntroductionDateDisplay = machine.Introduced.Value.ToString("MMMM d, yyyy");
|
||||
|
||||
// Populate processors
|
||||
if(machine.Processors != null)
|
||||
{
|
||||
foreach(ProcessorDto processor in machine.Processors)
|
||||
{
|
||||
var details = new List<string>();
|
||||
int speed = UntypedNodeExtractor.ExtractInt(processor.Speed);
|
||||
int gprSize = UntypedNodeExtractor.ExtractInt(processor.GprSize);
|
||||
int cores = UntypedNodeExtractor.ExtractInt(processor.Cores);
|
||||
|
||||
if(speed > 0) details.Add($"{speed} MHz");
|
||||
if(gprSize > 0) details.Add($"{gprSize} bits");
|
||||
if(cores > 1) details.Add($"{cores} cores");
|
||||
|
||||
Processors.Add(new ProcessorDisplayItem
|
||||
{
|
||||
DisplayName = processor.Name ?? string.Empty,
|
||||
Manufacturer = processor.Company ?? string.Empty,
|
||||
HasDetails = details.Count > 0,
|
||||
DetailsText = string.Join(", ", details)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Populate memory
|
||||
if(machine.Memory != null)
|
||||
{
|
||||
foreach(MemoryDto mem in machine.Memory)
|
||||
{
|
||||
long size = UntypedNodeExtractor.ExtractLong(mem.Size);
|
||||
|
||||
string sizeStr = size > 0
|
||||
? size > 1024 ? $"{size} bytes ({size.Bytes().Humanize()})" : $"{size} bytes"
|
||||
: "Unknown";
|
||||
|
||||
// Get humanized memory usage description
|
||||
string usageDescription = mem.Usage.HasValue
|
||||
? ((MemoryUsage)mem.Usage.Value).Humanize()
|
||||
: "Unknown";
|
||||
|
||||
Memory.Add(new MemoryDisplayItem
|
||||
{
|
||||
SizeDisplay = sizeStr,
|
||||
TypeDisplay = usageDescription
|
||||
});
|
||||
}
|
||||
} // Populate GPUs
|
||||
|
||||
if(machine.Gpus != null)
|
||||
{
|
||||
foreach(GpuDto gpu in machine.Gpus)
|
||||
{
|
||||
Gpus.Add(new GpuDisplayItem
|
||||
{
|
||||
DisplayName = gpu.Name ?? string.Empty,
|
||||
Manufacturer = gpu.Company ?? string.Empty,
|
||||
HasManufacturer = !string.IsNullOrEmpty(gpu.Company)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Populate sound synthesizers
|
||||
if(machine.SoundSynthesizers != null)
|
||||
{
|
||||
foreach(SoundSynthDto synth in machine.SoundSynthesizers)
|
||||
{
|
||||
var details = new List<string>();
|
||||
int voices = UntypedNodeExtractor.ExtractInt(synth.Voices);
|
||||
|
||||
if(voices > 0) details.Add($"{voices} voices");
|
||||
|
||||
SoundSynthesizers.Add(new SoundSynthesizerDisplayItem
|
||||
{
|
||||
DisplayName = synth.Name ?? string.Empty,
|
||||
HasDetails = details.Count > 0,
|
||||
DetailsText = string.Join(", ", details)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Populate storage
|
||||
if(machine.Storage != null)
|
||||
{
|
||||
foreach(StorageDto storage in machine.Storage)
|
||||
{
|
||||
long capacity = UntypedNodeExtractor.ExtractLong(storage.Capacity);
|
||||
|
||||
string displayText = capacity > 0
|
||||
? capacity > 1024
|
||||
? $"{capacity} bytes ({capacity.Bytes().Humanize()})"
|
||||
: $"{capacity} bytes"
|
||||
: "Storage";
|
||||
|
||||
// Get humanized storage type description
|
||||
string typeNote = storage.Type.HasValue ? ((StorageType)storage.Type.Value).Humanize() : "Unknown";
|
||||
|
||||
Storage.Add(new StorageDisplayItem
|
||||
{
|
||||
DisplayText = displayText,
|
||||
TypeNote = typeNote
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
UpdateVisibilities();
|
||||
IsDataLoaded = true;
|
||||
IsLoading = false;
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error loading machine {MachineId}", machineId);
|
||||
HasError = true;
|
||||
ErrorMessage = ex.Message;
|
||||
IsLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateVisibilities()
|
||||
{
|
||||
ShowIntroductionDate =
|
||||
!string.IsNullOrEmpty(IntroductionDateDisplay) ? Visibility.Visible : Visibility.Collapsed;
|
||||
|
||||
ShowFamily = !string.IsNullOrEmpty(FamilyName) ? Visibility.Visible : Visibility.Collapsed;
|
||||
ShowModel = !string.IsNullOrEmpty(ModelName) ? Visibility.Visible : Visibility.Collapsed;
|
||||
|
||||
ShowFamilyOrModel = ShowFamily == Visibility.Visible || ShowModel == Visibility.Visible
|
||||
? Visibility.Visible
|
||||
: Visibility.Collapsed;
|
||||
|
||||
ShowProcessors = Processors.Count > 0 ? Visibility.Visible : Visibility.Collapsed;
|
||||
ShowMemory = Memory.Count > 0 ? Visibility.Visible : Visibility.Collapsed;
|
||||
ShowGpus = Gpus.Count > 0 ? Visibility.Visible : Visibility.Collapsed;
|
||||
ShowSoundSynthesizers = SoundSynthesizers.Count > 0 ? Visibility.Visible : Visibility.Collapsed;
|
||||
ShowStorage = Storage.Count > 0 ? Visibility.Visible : Visibility.Collapsed;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Display item for processor information
|
||||
/// </summary>
|
||||
public class ProcessorDisplayItem
|
||||
{
|
||||
public string DisplayName { get; set; } = string.Empty;
|
||||
public string Manufacturer { get; set; } = string.Empty;
|
||||
public bool HasDetails { get; set; }
|
||||
public string DetailsText { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Display item for memory information
|
||||
/// </summary>
|
||||
public class MemoryDisplayItem
|
||||
{
|
||||
public string SizeDisplay { get; set; } = string.Empty;
|
||||
public string TypeDisplay { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Display item for GPU information
|
||||
/// </summary>
|
||||
public class GpuDisplayItem
|
||||
{
|
||||
public string DisplayName { get; set; } = string.Empty;
|
||||
public string Manufacturer { get; set; } = string.Empty;
|
||||
public bool HasManufacturer { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Display item for sound synthesizer information
|
||||
/// </summary>
|
||||
public class SoundSynthesizerDisplayItem
|
||||
{
|
||||
public string DisplayName { get; set; } = string.Empty;
|
||||
public bool HasDetails { get; set; }
|
||||
public string DetailsText { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Display item for storage information
|
||||
/// </summary>
|
||||
public class StorageDisplayItem
|
||||
{
|
||||
public string DisplayText { get; set; } = string.Empty;
|
||||
public string TypeNote { get; set; } = string.Empty;
|
||||
}
|
||||
177
Marechai.App/Presentation/ViewModels/MainViewModel.cs
Normal file
177
Marechai.App/Presentation/ViewModels/MainViewModel.cs
Normal file
@@ -0,0 +1,177 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using Uno.Extensions.Navigation;
|
||||
|
||||
namespace Marechai.App.Presentation.ViewModels;
|
||||
|
||||
public partial class MainViewModel : ObservableObject
|
||||
{
|
||||
private readonly IStringLocalizer _localizer;
|
||||
private readonly INavigator _navigator;
|
||||
[ObservableProperty]
|
||||
private bool _isSidebarOpen = true;
|
||||
[ObservableProperty]
|
||||
private Dictionary<string, string> _localizedStrings = new();
|
||||
[ObservableProperty]
|
||||
private string _loginLogoutButtonText = "";
|
||||
|
||||
[ObservableProperty]
|
||||
private string? _name;
|
||||
[ObservableProperty]
|
||||
private NewsViewModel? _newsViewModel;
|
||||
[ObservableProperty]
|
||||
private bool _sidebarContentVisible = true;
|
||||
|
||||
public MainViewModel(IStringLocalizer localizer, IOptions<AppConfig> appInfo, INavigator navigator,
|
||||
NewsViewModel newsViewModel)
|
||||
{
|
||||
_navigator = navigator;
|
||||
_localizer = localizer;
|
||||
NewsViewModel = newsViewModel;
|
||||
Title = "Marechai";
|
||||
Title += $" - {localizer["ApplicationName"]}";
|
||||
if(appInfo?.Value?.Environment != null) Title += $" - {appInfo.Value.Environment}";
|
||||
|
||||
GoToSecond = new AsyncRelayCommand(GoToSecondView);
|
||||
|
||||
// Initialize localized strings
|
||||
InitializeLocalizedStrings();
|
||||
|
||||
// Initialize commands
|
||||
NavigateToNewsCommand = new AsyncRelayCommand(NavigateToMainAsync);
|
||||
NavigateToBooksCommand = new AsyncRelayCommand(() => NavigateTo("books"));
|
||||
NavigateToCompaniesCommand = new AsyncRelayCommand(() => NavigateTo("companies"));
|
||||
NavigateToComputersCommand = new AsyncRelayCommand(() => NavigateTo("computers"));
|
||||
NavigateToConsolesCommand = new AsyncRelayCommand(() => NavigateTo("consoles"));
|
||||
NavigateToDocumentsCommand = new AsyncRelayCommand(() => NavigateTo("documents"));
|
||||
NavigateToDumpsCommand = new AsyncRelayCommand(() => NavigateTo("dumps"));
|
||||
NavigateToGraphicalProcessingUnitsCommand = new AsyncRelayCommand(() => NavigateTo("gpus"));
|
||||
NavigateToMagazinesCommand = new AsyncRelayCommand(() => NavigateTo("magazines"));
|
||||
NavigateToPeopleCommand = new AsyncRelayCommand(() => NavigateTo("people"));
|
||||
NavigateToProcessorsCommand = new AsyncRelayCommand(() => NavigateTo("processors"));
|
||||
NavigateToSoftwareCommand = new AsyncRelayCommand(() => NavigateTo("software"));
|
||||
NavigateToSoundSynthesizersCommand = new AsyncRelayCommand(() => NavigateTo("soundsynthesizers"));
|
||||
NavigateToSettingsCommand = new AsyncRelayCommand(() => NavigateTo("settings"));
|
||||
LoginLogoutCommand = new RelayCommand(HandleLoginLogout);
|
||||
ToggleSidebarCommand = new RelayCommand(() => IsSidebarOpen = !IsSidebarOpen);
|
||||
|
||||
UpdateLoginLogoutButtonText();
|
||||
}
|
||||
|
||||
public string? Title { get; }
|
||||
|
||||
public ICommand GoToSecond { get; }
|
||||
|
||||
public ICommand NavigateToNewsCommand { get; }
|
||||
public ICommand NavigateToBooksCommand { get; }
|
||||
public ICommand NavigateToCompaniesCommand { get; }
|
||||
public ICommand NavigateToComputersCommand { get; }
|
||||
public ICommand NavigateToConsolesCommand { get; }
|
||||
public ICommand NavigateToDocumentsCommand { get; }
|
||||
public ICommand NavigateToDumpsCommand { get; }
|
||||
public ICommand NavigateToGraphicalProcessingUnitsCommand { get; }
|
||||
public ICommand NavigateToMagazinesCommand { get; }
|
||||
public ICommand NavigateToPeopleCommand { get; }
|
||||
public ICommand NavigateToProcessorsCommand { get; }
|
||||
public ICommand NavigateToSoftwareCommand { get; }
|
||||
public ICommand NavigateToSoundSynthesizersCommand { get; }
|
||||
public ICommand NavigateToSettingsCommand { get; }
|
||||
public ICommand LoginLogoutCommand { get; }
|
||||
public ICommand ToggleSidebarCommand { get; }
|
||||
|
||||
private void InitializeLocalizedStrings()
|
||||
{
|
||||
LocalizedStrings = new Dictionary<string, string>
|
||||
{
|
||||
{
|
||||
"News", _localizer["News"]
|
||||
},
|
||||
{
|
||||
"Books", _localizer["Books"]
|
||||
},
|
||||
{
|
||||
"Companies", _localizer["Companies"]
|
||||
},
|
||||
{
|
||||
"Computers", _localizer["Computers"]
|
||||
},
|
||||
{
|
||||
"Consoles", _localizer["Consoles"]
|
||||
},
|
||||
{
|
||||
"Documents", _localizer["Documents"]
|
||||
},
|
||||
{
|
||||
"Dumps", _localizer["Dumps"]
|
||||
},
|
||||
{
|
||||
"GraphicalProcessingUnits", _localizer["GraphicalProcessingUnits"]
|
||||
},
|
||||
{
|
||||
"Magazines", _localizer["Magazines"]
|
||||
},
|
||||
{
|
||||
"People", _localizer["People"]
|
||||
},
|
||||
{
|
||||
"Processors", _localizer["Processors"]
|
||||
},
|
||||
{
|
||||
"Software", _localizer["Software"]
|
||||
},
|
||||
{
|
||||
"SoundSynthesizers", _localizer["SoundSynthesizers"]
|
||||
},
|
||||
{
|
||||
"Settings", _localizer["Settings"]
|
||||
},
|
||||
{
|
||||
"Login", _localizer["Login"]
|
||||
},
|
||||
{
|
||||
"Logout", _localizer["Logout"]
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void UpdateLoginLogoutButtonText()
|
||||
{
|
||||
// TODO: Check if user is logged in
|
||||
// For now, always show "Login"
|
||||
LoginLogoutButtonText = LocalizedStrings["Login"];
|
||||
}
|
||||
|
||||
private static void HandleLoginLogout()
|
||||
{
|
||||
// TODO: Implement login/logout logic
|
||||
}
|
||||
|
||||
private async Task NavigateTo(string destination)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Navigate within the Main region using relative navigation
|
||||
// The "./" prefix means navigate within the current page's region
|
||||
await _navigator.NavigateRouteAsync(this, $"./{destination}");
|
||||
}
|
||||
catch(Exception)
|
||||
{
|
||||
// Navigation error - fail silently for now
|
||||
// TODO: Add error handling/logging
|
||||
}
|
||||
}
|
||||
|
||||
private async Task NavigateToMainAsync()
|
||||
{
|
||||
// Navigate to News page (the default/home page)
|
||||
await NavigateTo("News");
|
||||
}
|
||||
|
||||
private async Task GoToSecondView()
|
||||
{
|
||||
// Navigate to Second view model providing qualifier and data
|
||||
await _navigator.NavigateViewModelAsync<SecondViewModel>(this, "Second", new Entity(Name ?? ""));
|
||||
}
|
||||
}
|
||||
176
Marechai.App/Presentation/ViewModels/NewsViewModel.cs
Normal file
176
Marechai.App/Presentation/ViewModels/NewsViewModel.cs
Normal file
@@ -0,0 +1,176 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Threading.Tasks;
|
||||
using Marechai.App.Helpers;
|
||||
using Marechai.App.Presentation.Models;
|
||||
using Marechai.App.Services;
|
||||
using Marechai.Data;
|
||||
using Uno.Extensions.Navigation;
|
||||
|
||||
namespace Marechai.App.Presentation.ViewModels;
|
||||
|
||||
/// <summary>
|
||||
/// Wrapper for NewsDto with generated display text
|
||||
/// </summary>
|
||||
public class NewsItemViewModel
|
||||
{
|
||||
public required NewsDto News { get; init; }
|
||||
public required string DisplayText { get; init; }
|
||||
public required IAsyncRelayCommand<NewsDto> NavigateToItemCommand { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines if this news item can be navigated to (only computers and consoles)
|
||||
/// </summary>
|
||||
public bool CanNavigateToItem
|
||||
{
|
||||
get
|
||||
{
|
||||
if(News?.Type is null) return false;
|
||||
var type = (NewsType)News.Type.Value;
|
||||
|
||||
return type is NewsType.NewComputerInDb
|
||||
or NewsType.NewConsoleInDb
|
||||
or NewsType.UpdatedComputerInDb
|
||||
or NewsType.UpdatedConsoleInDb
|
||||
or NewsType.NewComputerInCollection
|
||||
or NewsType.NewConsoleInCollection
|
||||
or NewsType.UpdatedComputerInCollection
|
||||
or NewsType.UpdatedConsoleInCollection;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public partial class NewsViewModel : ObservableObject
|
||||
{
|
||||
private readonly IStringLocalizer _localizer;
|
||||
private readonly ILogger<NewsViewModel> _logger;
|
||||
private readonly INavigator _navigator;
|
||||
private readonly NewsService _newsService;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _errorMessage = string.Empty;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _hasError;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _isLoading;
|
||||
|
||||
[ObservableProperty]
|
||||
private ObservableCollection<NewsItemViewModel> _newsList = [];
|
||||
|
||||
public NewsViewModel(NewsService newsService, IStringLocalizer localizer, ILogger<NewsViewModel> logger,
|
||||
INavigator navigator)
|
||||
{
|
||||
_newsService = newsService;
|
||||
_localizer = localizer;
|
||||
_logger = logger;
|
||||
_navigator = navigator;
|
||||
LoadNews = new AsyncRelayCommand(LoadNewsAsync);
|
||||
}
|
||||
|
||||
public IAsyncRelayCommand LoadNews { get; }
|
||||
|
||||
[RelayCommand]
|
||||
private async Task NavigateToNewsItem(NewsDto news)
|
||||
{
|
||||
if(news?.Type is null) return;
|
||||
|
||||
var newsType = (NewsType)news.Type.Value;
|
||||
|
||||
// Only navigate for computer and console news items
|
||||
bool isComputerOrConsole = newsType is NewsType.NewComputerInDb
|
||||
or NewsType.NewConsoleInDb
|
||||
or NewsType.UpdatedComputerInDb
|
||||
or NewsType.UpdatedConsoleInDb
|
||||
or NewsType.NewComputerInCollection
|
||||
or NewsType.NewConsoleInCollection
|
||||
or NewsType.UpdatedComputerInCollection
|
||||
or NewsType.UpdatedConsoleInCollection;
|
||||
|
||||
if(!isComputerOrConsole) return;
|
||||
|
||||
// Extract the machine ID from AffectedId
|
||||
if(news.AffectedId is null) return;
|
||||
|
||||
int machineId = UntypedNodeExtractor.ExtractInt(news.AffectedId);
|
||||
|
||||
if(machineId <= 0) return;
|
||||
|
||||
// Navigate to machine view with source information
|
||||
var navParam = new MachineViewNavigationParameter
|
||||
{
|
||||
MachineId = machineId,
|
||||
NavigationSource = this
|
||||
};
|
||||
|
||||
await _navigator.NavigateViewModelAsync<MachineViewViewModel>(this, data: navParam);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper to extract int from UntypedNode
|
||||
/// </summary>
|
||||
/// <summary>
|
||||
/// Generates localized text based on NewsType
|
||||
/// </summary>
|
||||
private string GetLocalizedTextForNewsType(NewsType type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
NewsType.NewComputerInDb => _localizer["New computer in database"].Value,
|
||||
NewsType.NewConsoleInDb => _localizer["New console in database"].Value,
|
||||
NewsType.NewComputerInCollection => _localizer["New computer in collection"].Value,
|
||||
NewsType.NewConsoleInCollection => _localizer["New console in collection"].Value,
|
||||
NewsType.UpdatedComputerInDb => _localizer["Updated computer in database"].Value,
|
||||
NewsType.UpdatedConsoleInDb => _localizer["Updated console in database"].Value,
|
||||
NewsType.UpdatedComputerInCollection => _localizer["Updated computer in collection"].Value,
|
||||
NewsType.UpdatedConsoleInCollection => _localizer["Updated console in collection"].Value,
|
||||
_ => string.Empty
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads the latest news from the API
|
||||
/// </summary>
|
||||
private async Task LoadNewsAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
IsLoading = true;
|
||||
ErrorMessage = string.Empty;
|
||||
HasError = false;
|
||||
NewsList.Clear();
|
||||
|
||||
List<NewsDto> news = await _newsService.GetLatestNewsAsync();
|
||||
|
||||
if(news.Count == 0)
|
||||
{
|
||||
ErrorMessage = _localizer["No news available"].Value;
|
||||
HasError = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach(NewsDto item in news)
|
||||
{
|
||||
NewsList.Add(new NewsItemViewModel
|
||||
{
|
||||
News = item,
|
||||
DisplayText = GetLocalizedTextForNewsType((NewsType)(item.Type ?? 0)),
|
||||
NavigateToItemCommand = NavigateToNewsItemCommand
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError("Error loading news: {Exception}", ex.Message);
|
||||
ErrorMessage = _localizer["Failed to load news. Please try again later."].Value;
|
||||
HasError = true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsLoading = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Marechai.App/Presentation/ViewModels/SecondViewModel.cs
Normal file
3
Marechai.App/Presentation/ViewModels/SecondViewModel.cs
Normal file
@@ -0,0 +1,3 @@
|
||||
namespace Marechai.App.Presentation.ViewModels;
|
||||
|
||||
public record SecondViewModel(Entity Entity) {}
|
||||
12
Marechai.App/Presentation/ViewModels/ShellViewModel.cs
Normal file
12
Marechai.App/Presentation/ViewModels/ShellViewModel.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using Uno.Extensions.Navigation;
|
||||
|
||||
namespace Marechai.App.Presentation.ViewModels;
|
||||
|
||||
public class ShellViewModel
|
||||
{
|
||||
private readonly INavigator _navigator;
|
||||
|
||||
public ShellViewModel(INavigator navigator) => _navigator = navigator;
|
||||
|
||||
// Add code here to initialize or attach event handlers to singleton services
|
||||
}
|
||||
120
Marechai.App/Presentation/Views/CompaniesPage.xaml
Normal file
120
Marechai.App/Presentation/Views/CompaniesPage.xaml
Normal file
@@ -0,0 +1,120 @@
|
||||
<?xml version="1.0"
|
||||
encoding="utf-8"?>
|
||||
|
||||
<Page x:Class="Marechai.App.Presentation.Views.CompaniesPage"
|
||||
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"
|
||||
NavigationCacheMode="Required"
|
||||
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
|
||||
<Grid utu:SafeArea.Insets="VisibleBounds">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" /> <RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Header -->
|
||||
<utu:NavigationBar Grid.Row="0"
|
||||
Content="{Binding Path=Title}">
|
||||
<utu:NavigationBar.MainCommand>
|
||||
<AppBarButton Icon="Back"
|
||||
Label="Back"
|
||||
Command="{Binding GoBackCommand}"
|
||||
AutomationProperties.Name="Go back" />
|
||||
</utu:NavigationBar.MainCommand>
|
||||
</utu:NavigationBar>
|
||||
|
||||
<!-- Content -->
|
||||
<ScrollViewer Grid.Row="1">
|
||||
<StackPanel Padding="16"
|
||||
Spacing="16">
|
||||
|
||||
<!-- Company Count Display -->
|
||||
<StackPanel HorizontalAlignment="Center"
|
||||
Spacing="8">
|
||||
<TextBlock Text="{Binding CompanyCountText}"
|
||||
TextAlignment="Center"
|
||||
FontSize="18"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||
<TextBlock Text="{Binding CompanyCount}"
|
||||
TextAlignment="Center"
|
||||
FontSize="48"
|
||||
FontWeight="Bold"
|
||||
Foreground="{ThemeResource SystemAccentColor}" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- Search Box -->
|
||||
<AutoSuggestBox x:Name="CompaniesSearchBox"
|
||||
HorizontalAlignment="Stretch"
|
||||
PlaceholderText="Search companies..."
|
||||
Text="{Binding SearchQuery, Mode=TwoWay}"
|
||||
QuerySubmitted="OnSearchQuerySubmitted"
|
||||
TextChanged="OnSearchTextChanged">
|
||||
<AutoSuggestBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding Name}" />
|
||||
</DataTemplate>
|
||||
</AutoSuggestBox.ItemTemplate>
|
||||
</AutoSuggestBox>
|
||||
|
||||
<!-- 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>
|
||||
|
||||
<!-- Companies List -->
|
||||
<StackPanel Visibility="{Binding IsDataLoaded}"
|
||||
Spacing="8">
|
||||
<ItemsRepeater ItemsSource="{Binding CompaniesList}">
|
||||
<ItemsRepeater.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Button HorizontalAlignment="Stretch"
|
||||
Command="{Binding DataContext.NavigateToCompanyCommand, ElementName=PageRoot}"
|
||||
CommandParameter="{Binding}">
|
||||
<StackPanel Spacing="4"
|
||||
Padding="8">
|
||||
<TextBlock Text="{Binding Name}"
|
||||
FontSize="16"
|
||||
FontWeight="SemiBold" />
|
||||
<TextBlock Text="{Binding FoundationDateDisplay}"
|
||||
FontSize="12"
|
||||
Opacity="0.6" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
</DataTemplate>
|
||||
</ItemsRepeater.ItemTemplate>
|
||||
</ItemsRepeater>
|
||||
</StackPanel>
|
||||
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
|
||||
</Grid>
|
||||
|
||||
</Page>
|
||||
59
Marechai.App/Presentation/Views/CompaniesPage.xaml.cs
Normal file
59
Marechai.App/Presentation/Views/CompaniesPage.xaml.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
using Marechai.App.Presentation.ViewModels;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
|
||||
namespace Marechai.App.Presentation.Views;
|
||||
|
||||
public sealed partial class CompaniesPage : Page
|
||||
{
|
||||
public CompaniesPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContextChanged += CompaniesPage_DataContextChanged;
|
||||
Loaded += CompaniesPage_Loaded;
|
||||
}
|
||||
|
||||
private void CompaniesPage_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if(DataContext is not CompaniesViewModel viewModel) return;
|
||||
|
||||
// Trigger data loading
|
||||
_ = viewModel.LoadData.ExecuteAsync(null);
|
||||
}
|
||||
|
||||
private void CompaniesPage_DataContextChanged(FrameworkElement sender, DataContextChangedEventArgs args)
|
||||
{
|
||||
if(args.NewValue is CompaniesViewModel viewModel)
|
||||
{
|
||||
// Trigger data loading when data context changes
|
||||
_ = viewModel.LoadData.ExecuteAsync(null);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
base.OnNavigatedTo(e);
|
||||
|
||||
if(DataContext is CompaniesViewModel viewModel)
|
||||
{
|
||||
// Trigger data loading when navigating to the page
|
||||
_ = viewModel.LoadData.ExecuteAsync(null);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSearchTextChanged(AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args)
|
||||
{
|
||||
if(args.Reason == AutoSuggestionBoxTextChangeReason.UserInput)
|
||||
{
|
||||
// The two-way binding will automatically update SearchQuery in ViewModel,
|
||||
// which will trigger OnSearchQueryChanged and filter the list
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSearchQuerySubmitted(AutoSuggestBox sender, AutoSuggestBoxQuerySubmittedEventArgs args)
|
||||
{
|
||||
// The two-way binding will automatically update SearchQuery in ViewModel,
|
||||
// which will trigger OnSearchQueryChanged and filter the list
|
||||
}
|
||||
}
|
||||
273
Marechai.App/Presentation/Views/CompanyDetailPage.xaml
Normal file
273
Marechai.App/Presentation/Views/CompanyDetailPage.xaml
Normal file
@@ -0,0 +1,273 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Page x:Class="Marechai.App.Presentation.Views.CompanyDetailPage"
|
||||
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"
|
||||
NavigationCacheMode="Required"
|
||||
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
|
||||
<Grid utu:SafeArea.Insets="VisibleBounds">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Header -->
|
||||
<utu:NavigationBar Grid.Row="0"
|
||||
Content="{Binding Path=Title}">
|
||||
<utu:NavigationBar.MainCommand>
|
||||
<AppBarButton Icon="Back"
|
||||
Label="Back"
|
||||
Command="{Binding GoBackCommand}"
|
||||
AutomationProperties.Name="Go back" />
|
||||
</utu:NavigationBar.MainCommand>
|
||||
</utu:NavigationBar>
|
||||
|
||||
<!-- 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>
|
||||
|
||||
<!-- Company Details -->
|
||||
<StackPanel Visibility="{Binding IsDataLoaded}"
|
||||
Spacing="16">
|
||||
|
||||
<!-- Company Name -->
|
||||
<TextBlock Text="{Binding Company.Name}"
|
||||
FontSize="28"
|
||||
FontWeight="Bold"
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
<!-- Company Status -->
|
||||
<StackPanel Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||
CornerRadius="8"
|
||||
Padding="12"
|
||||
Spacing="8">
|
||||
<TextBlock Text="Status"
|
||||
FontSize="14"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||
<TextBlock Text="{Binding CompanyStatusDisplay}"
|
||||
FontSize="14"
|
||||
TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- Founded Date -->
|
||||
<StackPanel Visibility="{Binding Company.Founded, Converter={StaticResource ObjectToVisibilityConverter}}"
|
||||
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||
CornerRadius="8"
|
||||
Padding="12"
|
||||
Spacing="8">
|
||||
<TextBlock Text="Founded"
|
||||
FontSize="14"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||
<TextBlock Text="{Binding CompanyFoundedDateDisplay}"
|
||||
FontSize="14" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- Legal Name -->
|
||||
<StackPanel Visibility="{Binding Company.LegalName, Converter={StaticResource StringToVisibilityConverter}}"
|
||||
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||
CornerRadius="8"
|
||||
Padding="12"
|
||||
Spacing="8">
|
||||
<TextBlock Text="Legal Name"
|
||||
FontSize="14"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||
<TextBlock Text="{Binding Company.LegalName}"
|
||||
FontSize="14" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- Country -->
|
||||
<StackPanel Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||
CornerRadius="8"
|
||||
Padding="12"
|
||||
Spacing="8">
|
||||
<TextBlock Text="Country"
|
||||
FontSize="14"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||
<TextBlock Text="{Binding Company.Country}"
|
||||
FontSize="14" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- Address -->
|
||||
<StackPanel Visibility="{Binding Company.Address, Converter={StaticResource StringToVisibilityConverter}}"
|
||||
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||
CornerRadius="8"
|
||||
Padding="12"
|
||||
Spacing="8">
|
||||
<TextBlock Text="Address"
|
||||
FontSize="14"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||
<TextBlock TextWrapping="Wrap">
|
||||
<Run Text="{Binding Company.Address}" />
|
||||
<Run Text="{Binding Company.City}" />
|
||||
<Run Text="{Binding Company.PostalCode}" />
|
||||
<Run Text="{Binding Company.Province}" />
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Links Section -->
|
||||
<StackPanel Spacing="8">
|
||||
<TextBlock Text="Links"
|
||||
FontSize="14"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||
|
||||
<!-- Website -->
|
||||
<HyperlinkButton Visibility="{Binding Company.Website, Converter={StaticResource StringToVisibilityConverter}}"
|
||||
NavigateUri="{Binding Company.Website}">
|
||||
<TextBlock Text="Website" />
|
||||
</HyperlinkButton>
|
||||
|
||||
<!-- Twitter -->
|
||||
<HyperlinkButton Visibility="{Binding Company.Twitter, Converter={StaticResource StringToVisibilityConverter}}"
|
||||
Click="OnTwitterClick">
|
||||
<TextBlock Text="Twitter" />
|
||||
</HyperlinkButton>
|
||||
|
||||
<!-- Facebook -->
|
||||
<HyperlinkButton Visibility="{Binding Company.Facebook, Converter={StaticResource StringToVisibilityConverter}}"
|
||||
Click="OnFacebookClick">
|
||||
<TextBlock Text="Facebook" />
|
||||
</HyperlinkButton>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Computers Section -->
|
||||
<StackPanel Visibility="{Binding Computers.Count, Converter={StaticResource ZeroToVisibilityConverter}}"
|
||||
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}"
|
||||
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 Command="{Binding DataContext.NavigateToMachineCommand, ElementName=PageRoot}"
|
||||
CommandParameter="{Binding}"
|
||||
Padding="12,8"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Left">
|
||||
<TextBlock Text="{Binding Name}"
|
||||
FontSize="12"
|
||||
TextWrapping="Wrap" />
|
||||
</Button>
|
||||
</DataTemplate>
|
||||
</ItemsRepeater.ItemTemplate>
|
||||
</ItemsRepeater>
|
||||
</ScrollViewer>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Consoles Section -->
|
||||
<StackPanel Visibility="{Binding Consoles.Count, Converter={StaticResource ZeroToVisibilityConverter}}"
|
||||
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}"
|
||||
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 Command="{Binding DataContext.NavigateToMachineCommand, ElementName=PageRoot}"
|
||||
CommandParameter="{Binding}"
|
||||
Padding="12,8"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Left">
|
||||
<TextBlock Text="{Binding Name}"
|
||||
FontSize="12"
|
||||
TextWrapping="Wrap" />
|
||||
</Button>
|
||||
</DataTemplate>
|
||||
</ItemsRepeater.ItemTemplate>
|
||||
</ItemsRepeater>
|
||||
</ScrollViewer>
|
||||
</StackPanel>
|
||||
|
||||
</StackPanel>
|
||||
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
|
||||
</Grid>
|
||||
|
||||
</Page>
|
||||
77
Marechai.App/Presentation/Views/CompanyDetailPage.xaml.cs
Normal file
77
Marechai.App/Presentation/Views/CompanyDetailPage.xaml.cs
Normal file
@@ -0,0 +1,77 @@
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using Windows.System;
|
||||
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;
|
||||
|
||||
public sealed partial class CompanyDetailPage : Page
|
||||
{
|
||||
private object? _navigationSource;
|
||||
private int? _pendingCompanyId;
|
||||
|
||||
public CompanyDetailPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContextChanged += CompanyDetailPage_DataContextChanged;
|
||||
}
|
||||
|
||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
base.OnNavigatedTo(e);
|
||||
|
||||
int? companyId = null;
|
||||
|
||||
// Handle both int and CompanyDetailNavigationParameter
|
||||
if(e.Parameter is int intId)
|
||||
companyId = intId;
|
||||
else if(e.Parameter is CompanyDetailNavigationParameter navParam)
|
||||
{
|
||||
companyId = navParam.CompanyId;
|
||||
_navigationSource = navParam.NavigationSource;
|
||||
}
|
||||
|
||||
if(companyId.HasValue)
|
||||
{
|
||||
_pendingCompanyId = companyId;
|
||||
|
||||
if(DataContext is CompanyDetailViewModel viewModel)
|
||||
{
|
||||
viewModel.CompanyId = companyId.Value;
|
||||
_ = viewModel.LoadData.ExecuteAsync(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CompanyDetailPage_DataContextChanged(FrameworkElement sender, DataContextChangedEventArgs args)
|
||||
{
|
||||
if(DataContext is CompanyDetailViewModel viewModel && _pendingCompanyId.HasValue)
|
||||
{
|
||||
viewModel.CompanyId = _pendingCompanyId.Value;
|
||||
_ = viewModel.LoadData.ExecuteAsync(null);
|
||||
}
|
||||
}
|
||||
|
||||
private async void OnTwitterClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if(DataContext is CompanyDetailViewModel viewModel && viewModel.Company?.Twitter is not null)
|
||||
{
|
||||
var uri = new Uri($"https://www.twitter.com/{viewModel.Company.Twitter}");
|
||||
await Launcher.LaunchUriAsync(uri);
|
||||
}
|
||||
}
|
||||
|
||||
private async void OnFacebookClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if(DataContext is CompanyDetailViewModel viewModel && viewModel.Company?.Facebook is not null)
|
||||
{
|
||||
var uri = new Uri($"https://www.facebook.com/{viewModel.Company.Facebook}");
|
||||
await Launcher.LaunchUriAsync(uri);
|
||||
}
|
||||
}
|
||||
}
|
||||
261
Marechai.App/Presentation/Views/ComputersListPage.xaml
Normal file
261
Marechai.App/Presentation/Views/ComputersListPage.xaml
Normal file
@@ -0,0 +1,261 @@
|
||||
<?xml version="1.0"
|
||||
encoding="utf-8"?>
|
||||
|
||||
<Page x:Class="Marechai.App.Presentation.Views.ComputersListPage"
|
||||
x:Name="PageRoot"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
NavigationCacheMode="Required"
|
||||
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
|
||||
<Grid RowSpacing="0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" /> <RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Header with Back Button and Title -->
|
||||
<Grid Grid.Row="0"
|
||||
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||
BorderBrush="{ThemeResource DividerStrokeColorDefaultBrush}"
|
||||
BorderThickness="0,0,0,1"
|
||||
Padding="16,12,16,12">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- Back Button -->
|
||||
<Button Grid.Column="0"
|
||||
Command="{Binding GoBackCommand}"
|
||||
Style="{ThemeResource AlternateButtonStyle}"
|
||||
ToolTipService.ToolTip="Go back"
|
||||
Padding="8"
|
||||
MinWidth="44"
|
||||
MinHeight="44"
|
||||
VerticalAlignment="Center">
|
||||
<FontIcon Glyph=""
|
||||
FontSize="16" />
|
||||
</Button>
|
||||
|
||||
<!-- Page Title -->
|
||||
<StackPanel Grid.Column="1"
|
||||
Margin="16,0,0,0"
|
||||
VerticalAlignment="Center">
|
||||
<TextBlock Text="{Binding PageTitle}"
|
||||
FontSize="20"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{ThemeResource TextControlForeground}" />
|
||||
<TextBlock Text="{Binding FilterDescription}"
|
||||
FontSize="12"
|
||||
Foreground="{ThemeResource SystemBaseMediumColor}"
|
||||
Margin="0,4,0,0" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<!-- Main Content -->
|
||||
<Grid Grid.Row="1">
|
||||
|
||||
<!-- Loading State -->
|
||||
<StackPanel Visibility="{Binding IsLoading}"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center"
|
||||
Padding="32"
|
||||
Spacing="16">
|
||||
<ProgressRing IsActive="True"
|
||||
IsIndeterminate="True"
|
||||
Height="64"
|
||||
Width="64"
|
||||
Foreground="{ThemeResource SystemAccentColor}" />
|
||||
<TextBlock Text="Loading computers..."
|
||||
FontSize="14"
|
||||
TextAlignment="Center"
|
||||
Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- Error State -->
|
||||
<StackPanel Visibility="{Binding HasError}"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center"
|
||||
Padding="24"
|
||||
Spacing="16"
|
||||
MaxWidth="400">
|
||||
<InfoBar IsOpen="True"
|
||||
Severity="Error"
|
||||
Title="Unable to Load Computers"
|
||||
Message="{Binding ErrorMessage}"
|
||||
IsClosable="False" />
|
||||
<Button Content="Retry"
|
||||
Command="{Binding LoadData}"
|
||||
HorizontalAlignment="Center"
|
||||
Style="{ThemeResource AccentButtonStyle}" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- Computers List -->
|
||||
<Grid Visibility="{Binding IsDataLoaded}">
|
||||
<ScrollViewer VerticalScrollBarVisibility="Auto"
|
||||
HorizontalScrollBarVisibility="Disabled">
|
||||
<Grid Padding="8">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" /> <RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Count Header -->
|
||||
<StackPanel Grid.Row="0"
|
||||
Padding="16,12"
|
||||
Orientation="Horizontal"
|
||||
Spacing="4">
|
||||
<TextBlock FontSize="12"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{ThemeResource SystemBaseMediumColor}"
|
||||
Text="RESULTS:" />
|
||||
<TextBlock FontSize="12"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{ThemeResource SystemBaseMediumColor}"
|
||||
Text="{Binding ComputersList.Count}" />
|
||||
<TextBlock FontSize="12"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{ThemeResource SystemBaseMediumColor}"
|
||||
Text="computers" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- Computers List -->
|
||||
<ItemsControl Grid.Row="1"
|
||||
ItemsSource="{Binding ComputersList}"
|
||||
Padding="0"
|
||||
Margin="0,8,0,0"
|
||||
HorizontalAlignment="Stretch">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Orientation="Vertical"
|
||||
Spacing="0"
|
||||
HorizontalAlignment="Stretch" />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Button Padding="0"
|
||||
Margin="0,0,0,8"
|
||||
MinHeight="80"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
VerticalContentAlignment="Stretch"
|
||||
HorizontalAlignment="Stretch"
|
||||
Command="{Binding DataContext.NavigateToComputerCommand, ElementName=PageRoot}"
|
||||
CommandParameter="{Binding}"
|
||||
Background="Transparent"
|
||||
BorderThickness="0">
|
||||
<Button.Template>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Grid MinHeight="80"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch">
|
||||
<!-- Shadow effect -->
|
||||
<Border x:Name="ShadowBorder"
|
||||
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="8"
|
||||
Padding="16,12"
|
||||
Translation="0, 0, 4"
|
||||
VerticalAlignment="Stretch">
|
||||
<Border.Shadow>
|
||||
<ThemeShadow />
|
||||
</Border.Shadow>
|
||||
|
||||
<Grid ColumnSpacing="16">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- Computer Info -->
|
||||
<StackPanel Grid.Column="0"
|
||||
Spacing="8"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Stretch">
|
||||
<TextBlock Text="{Binding Name}"
|
||||
FontSize="16"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{ThemeResource TextControlForeground}"
|
||||
TextTrimming="CharacterEllipsis" />
|
||||
<Grid ColumnSpacing="16"
|
||||
Height="20"
|
||||
VerticalAlignment="Center">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<StackPanel Grid.Column="0"
|
||||
Orientation="Horizontal"
|
||||
Spacing="6"
|
||||
VerticalAlignment="Center">
|
||||
<FontIcon Glyph=""
|
||||
FontSize="14"
|
||||
Foreground="{ThemeResource SystemAccentColor}" />
|
||||
<TextBlock Text="{Binding Manufacturer}"
|
||||
FontSize="13"
|
||||
Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Grid.Column="1"
|
||||
Orientation="Horizontal"
|
||||
Spacing="6"
|
||||
VerticalAlignment="Center">
|
||||
<FontIcon Glyph=""
|
||||
FontSize="14"
|
||||
Foreground="{ThemeResource SystemAccentColor}" />
|
||||
<TextBlock FontSize="13"
|
||||
Foreground="{ThemeResource SystemBaseMediumColor}">
|
||||
<Run Text="{Binding Year}" />
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Navigation Arrow -->
|
||||
<StackPanel Grid.Column="1"
|
||||
VerticalAlignment="Center">
|
||||
<FontIcon Glyph=""
|
||||
FontSize="18"
|
||||
Foreground="{ThemeResource SystemAccentColor}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal" />
|
||||
<VisualState x:Name="PointerOver">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ShadowBorder.Background"
|
||||
Value="{ThemeResource CardBackgroundFillColorSecondaryBrush}" />
|
||||
<Setter Target="ShadowBorder.Translation"
|
||||
Value="0, -2, 8" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Pressed">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ShadowBorder.Background"
|
||||
Value="{ThemeResource CardBackgroundFillColorTertiaryBrush}" />
|
||||
<Setter Target="ShadowBorder.Translation"
|
||||
Value="0, 0, 2" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Button.Template>
|
||||
</Button>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
|
||||
</Page>
|
||||
37
Marechai.App/Presentation/Views/ComputersListPage.xaml.cs
Normal file
37
Marechai.App/Presentation/Views/ComputersListPage.xaml.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using Marechai.App.Presentation.ViewModels;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Marechai.App.Presentation.Views;
|
||||
|
||||
/// <summary>
|
||||
/// Professional list view for displaying computers filtered by letter, year, or all.
|
||||
/// Features responsive layout, modern styling, and smooth navigation.
|
||||
/// </summary>
|
||||
public sealed partial class ComputersListPage : Page
|
||||
{
|
||||
public ComputersListPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
Loaded += ComputersListPage_Loaded;
|
||||
DataContextChanged += ComputersListPage_DataContextChanged;
|
||||
}
|
||||
|
||||
private void ComputersListPage_DataContextChanged(FrameworkElement sender, DataContextChangedEventArgs args)
|
||||
{
|
||||
if(DataContext is ComputersListViewModel vm)
|
||||
{
|
||||
// Load data when DataContext is set
|
||||
vm.LoadData.Execute(null);
|
||||
}
|
||||
}
|
||||
|
||||
private void ComputersListPage_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if(DataContext is ComputersListViewModel vm)
|
||||
{
|
||||
// Load data when page is loaded (fallback)
|
||||
vm.LoadData.Execute(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
311
Marechai.App/Presentation/Views/ComputersPage.xaml
Normal file
311
Marechai.App/Presentation/Views/ComputersPage.xaml
Normal file
@@ -0,0 +1,311 @@
|
||||
<?xml version="1.0"
|
||||
encoding="utf-8"?>
|
||||
|
||||
<Page x:Class="Marechai.App.Presentation.Views.ComputersPage"
|
||||
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"
|
||||
NavigationCacheMode="Required"
|
||||
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
|
||||
<Grid utu:SafeArea.Insets="VisibleBounds">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" /> <RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Header -->
|
||||
<utu:NavigationBar Grid.Row="0"
|
||||
Content="{Binding Path=Title}">
|
||||
<utu:NavigationBar.MainCommand>
|
||||
<AppBarButton Icon="Back"
|
||||
Label="Back"
|
||||
Command="{Binding GoBackCommand}"
|
||||
AutomationProperties.Name="Go back" />
|
||||
</utu:NavigationBar.MainCommand>
|
||||
</utu:NavigationBar>
|
||||
|
||||
<!-- Content -->
|
||||
<ScrollViewer Grid.Row="1">
|
||||
<StackPanel Padding="16"
|
||||
Spacing="24">
|
||||
|
||||
<!-- Computer Count Display -->
|
||||
<StackPanel HorizontalAlignment="Center"
|
||||
Spacing="8">
|
||||
<TextBlock Text="{Binding ComputerCountText}"
|
||||
TextAlignment="Center"
|
||||
FontSize="18"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||
<TextBlock Text="{Binding ComputerCount}"
|
||||
TextAlignment="Center"
|
||||
FontSize="48"
|
||||
FontWeight="Bold"
|
||||
Foreground="{ThemeResource SystemAccentColor}" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- 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>
|
||||
|
||||
<!-- Main Content (visible when loaded and no error) -->
|
||||
<StackPanel Visibility="{Binding IsDataLoaded}"
|
||||
Spacing="24">
|
||||
|
||||
<!-- Letters Grid Section -->
|
||||
<StackPanel Spacing="12">
|
||||
<TextBlock Text="Browse by Letter"
|
||||
FontSize="16"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||
<ItemsRepeater ItemsSource="{Binding LettersList}"
|
||||
Layout="{StaticResource LettersGridLayout}">
|
||||
<ItemsRepeater.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Button Content="{Binding}"
|
||||
Command="{Binding DataContext.NavigateByLetterCommand, ElementName=PageRoot}"
|
||||
CommandParameter="{Binding}"
|
||||
Style="{StaticResource KeyboardKeyButtonStyle}" />
|
||||
</DataTemplate>
|
||||
</ItemsRepeater.ItemTemplate>
|
||||
</ItemsRepeater>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Years Grid Section -->
|
||||
<StackPanel Spacing="12">
|
||||
<TextBlock Text="{Binding YearsGridTitle}"
|
||||
FontSize="16"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||
<ItemsRepeater ItemsSource="{Binding YearsList}"
|
||||
Layout="{StaticResource YearsGridLayout}">
|
||||
<ItemsRepeater.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Button Content="{Binding}"
|
||||
Command="{Binding DataContext.NavigateByYearCommand, ElementName=PageRoot}"
|
||||
CommandParameter="{Binding}"
|
||||
Style="{StaticResource KeyboardKeyButtonStyle}" />
|
||||
</DataTemplate>
|
||||
</ItemsRepeater.ItemTemplate>
|
||||
</ItemsRepeater>
|
||||
</StackPanel>
|
||||
|
||||
<!-- All Computers and Search Section -->
|
||||
<StackPanel Spacing="12">
|
||||
<Button Content="All Computers"
|
||||
Padding="16,12"
|
||||
HorizontalAlignment="Stretch"
|
||||
FontSize="16"
|
||||
FontWeight="SemiBold"
|
||||
Command="{Binding NavigateAllComputersCommand}"
|
||||
Style="{StaticResource AccentButtonStyle}" />
|
||||
|
||||
<!-- Search Field (placeholder for future implementation) -->
|
||||
<TextBox PlaceholderText="Search computers..."
|
||||
Padding="12"
|
||||
IsEnabled="False"
|
||||
Opacity="0.5" />
|
||||
</StackPanel>
|
||||
|
||||
</StackPanel>
|
||||
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
|
||||
</Grid>
|
||||
|
||||
<Page.Resources>
|
||||
<!-- Keyboard Key Button Style (revised: more padding, simplified borders to avoid clipping, darker scheme) -->
|
||||
<Style x:Key="KeyboardKeyButtonStyle"
|
||||
TargetType="Button">
|
||||
<!-- Base appearance -->
|
||||
<Setter Property="Foreground"
|
||||
Value="#1A1A1A" />
|
||||
<Setter Property="Background">
|
||||
<Setter.Value>
|
||||
<LinearGradientBrush StartPoint="0,0"
|
||||
EndPoint="0,1">
|
||||
<GradientStop Color="#D6D6D6"
|
||||
Offset="0" />
|
||||
<GradientStop Color="#C2C2C2"
|
||||
Offset="0.55" />
|
||||
<GradientStop Color="#B0B0B0"
|
||||
Offset="1" />
|
||||
</LinearGradientBrush>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Property="BorderBrush"
|
||||
Value="#7A7A7A" />
|
||||
<Setter Property="BorderThickness"
|
||||
Value="1" />
|
||||
<Setter Property="CornerRadius"
|
||||
Value="6" />
|
||||
<Setter Property="Padding"
|
||||
Value="14,12" /> <!-- Increased vertical padding to prevent cutoff -->
|
||||
<Setter Property="Margin"
|
||||
Value="4" />
|
||||
<Setter Property="FontFamily"
|
||||
Value="Segoe UI" />
|
||||
<Setter Property="FontWeight"
|
||||
Value="SemiBold" />
|
||||
<Setter Property="FontSize"
|
||||
Value="15" />
|
||||
<Setter Property="HorizontalAlignment"
|
||||
Value="Stretch" />
|
||||
<Setter Property="VerticalAlignment"
|
||||
Value="Stretch" />
|
||||
<Setter Property="HorizontalContentAlignment"
|
||||
Value="Center" />
|
||||
<Setter Property="VerticalContentAlignment"
|
||||
Value="Center" />
|
||||
<Setter Property="MinWidth"
|
||||
Value="52" />
|
||||
<Setter Property="MinHeight"
|
||||
Value="52" /> <!-- Larger min height avoids clipping ascenders/descenders -->
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Grid>
|
||||
<!-- Shadow (simple) -->
|
||||
<Border x:Name="Shadow"
|
||||
CornerRadius="6"
|
||||
Background="#33000000"
|
||||
Margin="2,4,4,2" />
|
||||
<!-- Key surface -->
|
||||
<Border x:Name="KeyBorder"
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
CornerRadius="{TemplateBinding CornerRadius}">
|
||||
<!-- Inner highlight & content -->
|
||||
<Grid>
|
||||
<Border CornerRadius="{TemplateBinding CornerRadius}"
|
||||
BorderBrush="#60FFFFFF"
|
||||
BorderThickness="1,1,0,0" />
|
||||
<Border CornerRadius="{TemplateBinding CornerRadius}"
|
||||
BorderBrush="#30000000"
|
||||
BorderThickness="0,0,1,1" />
|
||||
<ContentPresenter x:Name="ContentPresenter"
|
||||
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
Margin="0"
|
||||
TextWrapping="NoWrap" />
|
||||
</Grid>
|
||||
</Border>
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal" />
|
||||
<VisualState x:Name="PointerOver">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="KeyBorder.Background">
|
||||
<Setter.Value>
|
||||
<LinearGradientBrush StartPoint="0,0"
|
||||
EndPoint="0,1">
|
||||
<GradientStop Color="#E0E0E0"
|
||||
Offset="0" />
|
||||
<GradientStop Color="#CFCFCF"
|
||||
Offset="0.55" />
|
||||
<GradientStop Color="#BDBDBD"
|
||||
Offset="1" />
|
||||
</LinearGradientBrush>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Target="KeyBorder.BorderBrush"
|
||||
Value="#5F5F5F" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Pressed">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="KeyBorder.Background">
|
||||
<Setter.Value>
|
||||
<LinearGradientBrush StartPoint="0,0"
|
||||
EndPoint="0,1">
|
||||
<GradientStop Color="#9C9C9C"
|
||||
Offset="0" />
|
||||
<GradientStop Color="#A8A8A8"
|
||||
Offset="0.55" />
|
||||
<GradientStop Color="#B4B4B4"
|
||||
Offset="1" />
|
||||
</LinearGradientBrush>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Target="KeyBorder.BorderBrush"
|
||||
Value="#4A4A4A" />
|
||||
<Setter Target="KeyBorder.RenderTransform">
|
||||
<Setter.Value>
|
||||
<TranslateTransform Y="2" />
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Target="Shadow.Opacity"
|
||||
Value="0.15" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Disabled">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="KeyBorder.Opacity"
|
||||
Value="0.45" />
|
||||
<Setter Target="ContentPresenter.Foreground"
|
||||
Value="#777777" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
<VisualStateGroup x:Name="FocusStates">
|
||||
<VisualState x:Name="Focused">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="KeyBorder.BorderBrush"
|
||||
Value="#3A7AFE" />
|
||||
<Setter Target="KeyBorder.BorderThickness"
|
||||
Value="2" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Unfocused" />
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<!-- Responsive Grid Layouts -->
|
||||
<UniformGridLayout x:Key="LettersGridLayout"
|
||||
ItemsStretch="Fill"
|
||||
MinItemWidth="44"
|
||||
MinItemHeight="44"
|
||||
MaximumRowsOrColumns="13" />
|
||||
|
||||
<UniformGridLayout x:Key="YearsGridLayout"
|
||||
ItemsStretch="Fill"
|
||||
MinItemWidth="54"
|
||||
MinItemHeight="44"
|
||||
MaximumRowsOrColumns="10" />
|
||||
|
||||
</Page.Resources>
|
||||
|
||||
</Page>
|
||||
44
Marechai.App/Presentation/Views/ComputersPage.xaml.cs
Normal file
44
Marechai.App/Presentation/Views/ComputersPage.xaml.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using Marechai.App.Presentation.ViewModels;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
|
||||
namespace Marechai.App.Presentation.Views;
|
||||
|
||||
public sealed partial class ComputersPage : Page
|
||||
{
|
||||
public ComputersPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContextChanged += ComputersPage_DataContextChanged;
|
||||
Loaded += ComputersPage_Loaded;
|
||||
}
|
||||
|
||||
private void ComputersPage_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if(DataContext is not ComputersViewModel viewModel) return;
|
||||
|
||||
// Trigger data loading
|
||||
_ = viewModel.LoadData.ExecuteAsync(null);
|
||||
}
|
||||
|
||||
private void ComputersPage_DataContextChanged(FrameworkElement sender, DataContextChangedEventArgs args)
|
||||
{
|
||||
if(args.NewValue is ComputersViewModel viewModel)
|
||||
{
|
||||
// Trigger data loading when data context changes
|
||||
_ = viewModel.LoadData.ExecuteAsync(null);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
base.OnNavigatedTo(e);
|
||||
|
||||
if(DataContext is ComputersViewModel viewModel)
|
||||
{
|
||||
// Trigger data loading when navigating to the page
|
||||
_ = viewModel.LoadData.ExecuteAsync(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
261
Marechai.App/Presentation/Views/ConsolesListPage.xaml
Normal file
261
Marechai.App/Presentation/Views/ConsolesListPage.xaml
Normal file
@@ -0,0 +1,261 @@
|
||||
<?xml version="1.0"
|
||||
encoding="utf-8"?>
|
||||
|
||||
<Page x:Class="Marechai.App.Presentation.Views.ConsolesListPage"
|
||||
x:Name="PageRoot"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
NavigationCacheMode="Required"
|
||||
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
|
||||
<Grid RowSpacing="0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" /> <RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Header with Back Button and Title -->
|
||||
<Grid Grid.Row="0"
|
||||
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||
BorderBrush="{ThemeResource DividerStrokeColorDefaultBrush}"
|
||||
BorderThickness="0,0,0,1"
|
||||
Padding="16,12,16,12">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- Back Button -->
|
||||
<Button Grid.Column="0"
|
||||
Command="{Binding GoBackCommand}"
|
||||
Style="{ThemeResource AlternateButtonStyle}"
|
||||
ToolTipService.ToolTip="Go back"
|
||||
Padding="8"
|
||||
MinWidth="44"
|
||||
MinHeight="44"
|
||||
VerticalAlignment="Center">
|
||||
<FontIcon Glyph=""
|
||||
FontSize="16" />
|
||||
</Button>
|
||||
|
||||
<!-- Page Title -->
|
||||
<StackPanel Grid.Column="1"
|
||||
Margin="16,0,0,0"
|
||||
VerticalAlignment="Center">
|
||||
<TextBlock Text="{Binding PageTitle}"
|
||||
FontSize="20"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{ThemeResource TextControlForeground}" />
|
||||
<TextBlock Text="{Binding FilterDescription}"
|
||||
FontSize="12"
|
||||
Foreground="{ThemeResource SystemBaseMediumColor}"
|
||||
Margin="0,4,0,0" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<!-- Main Content -->
|
||||
<Grid Grid.Row="1">
|
||||
|
||||
<!-- Loading State -->
|
||||
<StackPanel Visibility="{Binding IsLoading}"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center"
|
||||
Padding="32"
|
||||
Spacing="16">
|
||||
<ProgressRing IsActive="True"
|
||||
IsIndeterminate="True"
|
||||
Height="64"
|
||||
Width="64"
|
||||
Foreground="{ThemeResource SystemAccentColor}" />
|
||||
<TextBlock Text="Loading consoles..."
|
||||
FontSize="14"
|
||||
TextAlignment="Center"
|
||||
Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- Error State -->
|
||||
<StackPanel Visibility="{Binding HasError}"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center"
|
||||
Padding="24"
|
||||
Spacing="16"
|
||||
MaxWidth="400">
|
||||
<InfoBar IsOpen="True"
|
||||
Severity="Error"
|
||||
Title="Unable to Load Consoles"
|
||||
Message="{Binding ErrorMessage}"
|
||||
IsClosable="False" />
|
||||
<Button Content="Retry"
|
||||
Command="{Binding LoadData}"
|
||||
HorizontalAlignment="Center"
|
||||
Style="{ThemeResource AccentButtonStyle}" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- Consoles List -->
|
||||
<Grid Visibility="{Binding IsDataLoaded}">
|
||||
<ScrollViewer VerticalScrollBarVisibility="Auto"
|
||||
HorizontalScrollBarVisibility="Disabled">
|
||||
<Grid Padding="8">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" /> <RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Count Header -->
|
||||
<StackPanel Grid.Row="0"
|
||||
Padding="16,12"
|
||||
Orientation="Horizontal"
|
||||
Spacing="4">
|
||||
<TextBlock FontSize="12"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{ThemeResource SystemBaseMediumColor}"
|
||||
Text="RESULTS:" />
|
||||
<TextBlock FontSize="12"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{ThemeResource SystemBaseMediumColor}"
|
||||
Text="{Binding ConsolesList.Count}" />
|
||||
<TextBlock FontSize="12"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{ThemeResource SystemBaseMediumColor}"
|
||||
Text="consoles" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- Consoles List -->
|
||||
<ItemsControl Grid.Row="1"
|
||||
ItemsSource="{Binding ConsolesList}"
|
||||
Padding="0"
|
||||
Margin="0,8,0,0"
|
||||
HorizontalAlignment="Stretch">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Orientation="Vertical"
|
||||
Spacing="0"
|
||||
HorizontalAlignment="Stretch" />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Button Padding="0"
|
||||
Margin="0,0,0,8"
|
||||
MinHeight="80"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
VerticalContentAlignment="Stretch"
|
||||
HorizontalAlignment="Stretch"
|
||||
Command="{Binding DataContext.NavigateToConsoleCommand, ElementName=PageRoot}"
|
||||
CommandParameter="{Binding}"
|
||||
Background="Transparent"
|
||||
BorderThickness="0">
|
||||
<Button.Template>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Grid MinHeight="80"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch">
|
||||
<!-- Shadow effect -->
|
||||
<Border x:Name="ShadowBorder"
|
||||
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="8"
|
||||
Padding="16,12"
|
||||
Translation="0, 0, 4"
|
||||
VerticalAlignment="Stretch">
|
||||
<Border.Shadow>
|
||||
<ThemeShadow />
|
||||
</Border.Shadow>
|
||||
|
||||
<Grid ColumnSpacing="16">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- Console Info -->
|
||||
<StackPanel Grid.Column="0"
|
||||
Spacing="8"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Stretch">
|
||||
<TextBlock Text="{Binding Name}"
|
||||
FontSize="16"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{ThemeResource TextControlForeground}"
|
||||
TextTrimming="CharacterEllipsis" />
|
||||
<Grid ColumnSpacing="16"
|
||||
Height="20"
|
||||
VerticalAlignment="Center">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<StackPanel Grid.Column="0"
|
||||
Orientation="Horizontal"
|
||||
Spacing="6"
|
||||
VerticalAlignment="Center">
|
||||
<FontIcon Glyph=""
|
||||
FontSize="14"
|
||||
Foreground="{ThemeResource SystemAccentColor}" />
|
||||
<TextBlock Text="{Binding Manufacturer}"
|
||||
FontSize="13"
|
||||
Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Grid.Column="1"
|
||||
Orientation="Horizontal"
|
||||
Spacing="6"
|
||||
VerticalAlignment="Center">
|
||||
<FontIcon Glyph=""
|
||||
FontSize="14"
|
||||
Foreground="{ThemeResource SystemAccentColor}" />
|
||||
<TextBlock FontSize="13"
|
||||
Foreground="{ThemeResource SystemBaseMediumColor}">
|
||||
<Run Text="{Binding Year}" />
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Navigation Arrow -->
|
||||
<StackPanel Grid.Column="1"
|
||||
VerticalAlignment="Center">
|
||||
<FontIcon Glyph=""
|
||||
FontSize="18"
|
||||
Foreground="{ThemeResource SystemAccentColor}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal" />
|
||||
<VisualState x:Name="PointerOver">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ShadowBorder.Background"
|
||||
Value="{ThemeResource CardBackgroundFillColorSecondaryBrush}" />
|
||||
<Setter Target="ShadowBorder.Translation"
|
||||
Value="0, -2, 8" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Pressed">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ShadowBorder.Background"
|
||||
Value="{ThemeResource CardBackgroundFillColorTertiaryBrush}" />
|
||||
<Setter Target="ShadowBorder.Translation"
|
||||
Value="0, 0, 2" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Button.Template>
|
||||
</Button>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
|
||||
</Page>
|
||||
37
Marechai.App/Presentation/Views/ConsolesListPage.xaml.cs
Normal file
37
Marechai.App/Presentation/Views/ConsolesListPage.xaml.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using Marechai.App.Presentation.ViewModels;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Marechai.App.Presentation.Views;
|
||||
|
||||
/// <summary>
|
||||
/// Professional list view for displaying consoles filtered by letter, year, or all.
|
||||
/// Features responsive layout, modern styling, and smooth navigation.
|
||||
/// </summary>
|
||||
public sealed partial class ConsolesListPage : Page
|
||||
{
|
||||
public ConsolesListPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
Loaded += ConsolesListPage_Loaded;
|
||||
DataContextChanged += ConsolesListPage_DataContextChanged;
|
||||
}
|
||||
|
||||
private void ConsolesListPage_DataContextChanged(FrameworkElement sender, DataContextChangedEventArgs args)
|
||||
{
|
||||
if(DataContext is ConsolesListViewModel vm)
|
||||
{
|
||||
// Load data when DataContext is set
|
||||
vm.LoadData.Execute(null);
|
||||
}
|
||||
}
|
||||
|
||||
private void ConsolesListPage_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if(DataContext is ConsolesListViewModel vm)
|
||||
{
|
||||
// Load data when page is loaded (fallback)
|
||||
vm.LoadData.Execute(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
297
Marechai.App/Presentation/Views/ConsolesPage.xaml
Normal file
297
Marechai.App/Presentation/Views/ConsolesPage.xaml
Normal file
@@ -0,0 +1,297 @@
|
||||
<?xml version="1.0"
|
||||
encoding="utf-8"?>
|
||||
|
||||
<Page x:Class="Marechai.App.Presentation.Views.ConsolesPage"
|
||||
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"
|
||||
NavigationCacheMode="Required"
|
||||
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
|
||||
<Grid utu:SafeArea.Insets="VisibleBounds">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" /> <RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Header -->
|
||||
<utu:NavigationBar Grid.Row="0"
|
||||
Content="{Binding Path=Title}">
|
||||
<utu:NavigationBar.MainCommand>
|
||||
<AppBarButton Icon="Back"
|
||||
Label="Back"
|
||||
Command="{Binding GoBackCommand}"
|
||||
AutomationProperties.Name="Go back" />
|
||||
</utu:NavigationBar.MainCommand>
|
||||
</utu:NavigationBar>
|
||||
|
||||
<!-- Content -->
|
||||
<ScrollViewer Grid.Row="1">
|
||||
<StackPanel Padding="16"
|
||||
Spacing="24">
|
||||
|
||||
<!-- Console Count Display -->
|
||||
<StackPanel HorizontalAlignment="Center"
|
||||
Spacing="8">
|
||||
<TextBlock Text="{Binding ConsoleCountText}"
|
||||
TextAlignment="Center"
|
||||
FontSize="18"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||
<TextBlock Text="{Binding ConsoleCount}"
|
||||
TextAlignment="Center"
|
||||
FontSize="48"
|
||||
FontWeight="Bold"
|
||||
Foreground="{ThemeResource SystemAccentColor}" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- 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>
|
||||
|
||||
<!-- Main Content (visible when loaded and no error) -->
|
||||
<StackPanel Visibility="{Binding IsDataLoaded}"
|
||||
Spacing="24">
|
||||
|
||||
<!-- Letters Grid Section -->
|
||||
<StackPanel Spacing="12">
|
||||
<TextBlock Text="Browse by Letter"
|
||||
FontSize="16"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||
<ItemsRepeater ItemsSource="{Binding LettersList}"
|
||||
Layout="{StaticResource LettersGridLayout}">
|
||||
<ItemsRepeater.ItemTemplate></ItemsRepeater.ItemTemplate>
|
||||
</ItemsRepeater>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Years Grid Section -->
|
||||
<StackPanel Spacing="12">
|
||||
<TextBlock Text="{Binding YearsGridTitle}"
|
||||
FontSize="16"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||
<ItemsRepeater ItemsSource="{Binding YearsList}"
|
||||
Layout="{StaticResource YearsGridLayout}">
|
||||
<ItemsRepeater.ItemTemplate></ItemsRepeater.ItemTemplate>
|
||||
</ItemsRepeater>
|
||||
</StackPanel>
|
||||
|
||||
<!-- All Consoles and Search Section -->
|
||||
<StackPanel Spacing="12">
|
||||
<Button Content="All Consoles"
|
||||
Padding="16,12"
|
||||
HorizontalAlignment="Stretch"
|
||||
FontSize="16"
|
||||
FontWeight="SemiBold"
|
||||
Command="{Binding NavigateAllConsolesCommand}"
|
||||
Style="{StaticResource AccentButtonStyle}" />
|
||||
|
||||
<!-- Search Field (placeholder for future implementation) -->
|
||||
<TextBox PlaceholderText="Search consoles..."
|
||||
Padding="12"
|
||||
IsEnabled="False"
|
||||
Opacity="0.5" />
|
||||
</StackPanel>
|
||||
|
||||
</StackPanel>
|
||||
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
|
||||
</Grid>
|
||||
|
||||
<Page.Resources>
|
||||
<!-- Keyboard Key Button Style (revised: more padding, simplified borders to avoid clipping, darker scheme) -->
|
||||
<Style x:Key="KeyboardKeyButtonStyle"
|
||||
TargetType="Button">
|
||||
<!-- Base appearance -->
|
||||
<Setter Property="Foreground"
|
||||
Value="#1A1A1A" />
|
||||
<Setter Property="Background">
|
||||
<Setter.Value>
|
||||
<LinearGradientBrush StartPoint="0,0"
|
||||
EndPoint="0,1">
|
||||
<GradientStop Color="#D6D6D6"
|
||||
Offset="0" />
|
||||
<GradientStop Color="#C2C2C2"
|
||||
Offset="0.55" />
|
||||
<GradientStop Color="#B0B0B0"
|
||||
Offset="1" />
|
||||
</LinearGradientBrush>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Property="BorderBrush"
|
||||
Value="#7A7A7A" />
|
||||
<Setter Property="BorderThickness"
|
||||
Value="1" />
|
||||
<Setter Property="CornerRadius"
|
||||
Value="6" />
|
||||
<Setter Property="Padding"
|
||||
Value="14,12" /> <!-- Increased vertical padding to prevent cutoff -->
|
||||
<Setter Property="Margin"
|
||||
Value="4" />
|
||||
<Setter Property="FontFamily"
|
||||
Value="Segoe UI" />
|
||||
<Setter Property="FontWeight"
|
||||
Value="SemiBold" />
|
||||
<Setter Property="FontSize"
|
||||
Value="15" />
|
||||
<Setter Property="HorizontalAlignment"
|
||||
Value="Stretch" />
|
||||
<Setter Property="VerticalAlignment"
|
||||
Value="Stretch" />
|
||||
<Setter Property="HorizontalContentAlignment"
|
||||
Value="Center" />
|
||||
<Setter Property="VerticalContentAlignment"
|
||||
Value="Center" />
|
||||
<Setter Property="MinWidth"
|
||||
Value="52" />
|
||||
<Setter Property="MinHeight"
|
||||
Value="52" /> <!-- Larger min height avoids clipping ascenders/descenders -->
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Grid>
|
||||
<!-- Shadow (simple) -->
|
||||
<Border x:Name="Shadow"
|
||||
CornerRadius="6"
|
||||
Background="#33000000"
|
||||
Margin="2,4,4,2" />
|
||||
<!-- Key surface -->
|
||||
<Border x:Name="KeyBorder"
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
CornerRadius="{TemplateBinding CornerRadius}">
|
||||
<!-- Inner highlight & content -->
|
||||
<Grid>
|
||||
<Border CornerRadius="{TemplateBinding CornerRadius}"
|
||||
BorderBrush="#60FFFFFF"
|
||||
BorderThickness="1,1,0,0" />
|
||||
<Border CornerRadius="{TemplateBinding CornerRadius}"
|
||||
BorderBrush="#30000000"
|
||||
BorderThickness="0,0,1,1" />
|
||||
<ContentPresenter x:Name="ContentPresenter"
|
||||
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
Margin="0"
|
||||
TextWrapping="NoWrap" />
|
||||
</Grid>
|
||||
</Border>
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal" />
|
||||
<VisualState x:Name="PointerOver">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="KeyBorder.Background">
|
||||
<Setter.Value>
|
||||
<LinearGradientBrush StartPoint="0,0"
|
||||
EndPoint="0,1">
|
||||
<GradientStop Color="#E0E0E0"
|
||||
Offset="0" />
|
||||
<GradientStop Color="#CFCFCF"
|
||||
Offset="0.55" />
|
||||
<GradientStop Color="#BDBDBD"
|
||||
Offset="1" />
|
||||
</LinearGradientBrush>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Target="KeyBorder.BorderBrush"
|
||||
Value="#5F5F5F" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Pressed">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="KeyBorder.Background">
|
||||
<Setter.Value>
|
||||
<LinearGradientBrush StartPoint="0,0"
|
||||
EndPoint="0,1">
|
||||
<GradientStop Color="#9C9C9C"
|
||||
Offset="0" />
|
||||
<GradientStop Color="#A8A8A8"
|
||||
Offset="0.55" />
|
||||
<GradientStop Color="#B4B4B4"
|
||||
Offset="1" />
|
||||
</LinearGradientBrush>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Target="KeyBorder.BorderBrush"
|
||||
Value="#4A4A4A" />
|
||||
<Setter Target="KeyBorder.RenderTransform">
|
||||
<Setter.Value>
|
||||
<TranslateTransform Y="2" />
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Target="Shadow.Opacity"
|
||||
Value="0.15" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Disabled">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="KeyBorder.Opacity"
|
||||
Value="0.45" />
|
||||
<Setter Target="ContentPresenter.Foreground"
|
||||
Value="#777777" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
<VisualStateGroup x:Name="FocusStates">
|
||||
<VisualState x:Name="Focused">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="KeyBorder.BorderBrush"
|
||||
Value="#3A7AFE" />
|
||||
<Setter Target="KeyBorder.BorderThickness"
|
||||
Value="2" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Unfocused" />
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<!-- Responsive Grid Layouts -->
|
||||
<UniformGridLayout x:Key="LettersGridLayout"
|
||||
ItemsStretch="Fill"
|
||||
MinItemWidth="44"
|
||||
MinItemHeight="44"
|
||||
MaximumRowsOrColumns="13" />
|
||||
|
||||
<UniformGridLayout x:Key="YearsGridLayout"
|
||||
ItemsStretch="Fill"
|
||||
MinItemWidth="54"
|
||||
MinItemHeight="44"
|
||||
MaximumRowsOrColumns="10" />
|
||||
|
||||
</Page.Resources>
|
||||
|
||||
</Page>
|
||||
44
Marechai.App/Presentation/Views/ConsolesPage.xaml.cs
Normal file
44
Marechai.App/Presentation/Views/ConsolesPage.xaml.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using Marechai.App.Presentation.ViewModels;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
|
||||
namespace Marechai.App.Presentation.Views;
|
||||
|
||||
public sealed partial class ConsolesPage : Page
|
||||
{
|
||||
public ConsolesPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContextChanged += ConsolesPage_DataContextChanged;
|
||||
Loaded += ConsolesPage_Loaded;
|
||||
}
|
||||
|
||||
private void ConsolesPage_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if(DataContext is not ConsolesViewModel viewModel) return;
|
||||
|
||||
// Trigger data loading
|
||||
_ = viewModel.LoadData.ExecuteAsync(null);
|
||||
}
|
||||
|
||||
private void ConsolesPage_DataContextChanged(FrameworkElement sender, DataContextChangedEventArgs args)
|
||||
{
|
||||
if(args.NewValue is ConsolesViewModel viewModel)
|
||||
{
|
||||
// Trigger data loading when data context changes
|
||||
_ = viewModel.LoadData.ExecuteAsync(null);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
base.OnNavigatedTo(e);
|
||||
|
||||
if(DataContext is ConsolesViewModel viewModel)
|
||||
{
|
||||
// Trigger data loading when navigating to the page
|
||||
_ = viewModel.LoadData.ExecuteAsync(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
385
Marechai.App/Presentation/Views/MachineViewPage.xaml
Normal file
385
Marechai.App/Presentation/Views/MachineViewPage.xaml
Normal file
@@ -0,0 +1,385 @@
|
||||
<?xml version="1.0"
|
||||
encoding="utf-8"?>
|
||||
|
||||
<Page x:Class="Marechai.App.Presentation.Views.MachineViewPage"
|
||||
x:Name="PageRoot"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
NavigationCacheMode="Disabled"
|
||||
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
|
||||
<Grid RowSpacing="0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" /> <RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Header with Back Button -->
|
||||
<Grid Grid.Row="0"
|
||||
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||
BorderBrush="{ThemeResource DividerStrokeColorDefaultBrush}"
|
||||
BorderThickness="0,0,0,1"
|
||||
Padding="12,12,16,12">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- Back Button -->
|
||||
<Button Grid.Column="0"
|
||||
Command="{Binding GoBackCommand}"
|
||||
Style="{ThemeResource AlternateButtonStyle}"
|
||||
ToolTipService.ToolTip="Go back"
|
||||
Padding="8"
|
||||
MinWidth="44"
|
||||
MinHeight="44"
|
||||
VerticalAlignment="Center">
|
||||
<FontIcon Glyph=""
|
||||
FontSize="16" />
|
||||
</Button>
|
||||
|
||||
<!-- Title Section -->
|
||||
<StackPanel Grid.Column="1"
|
||||
Margin="12,0,0,0"
|
||||
VerticalAlignment="Center">
|
||||
<TextBlock Text="{Binding MachineName}"
|
||||
FontSize="20"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{ThemeResource TextControlForeground}"
|
||||
TextTrimming="CharacterEllipsis" />
|
||||
<TextBlock Text="{Binding CompanyName}"
|
||||
FontSize="12"
|
||||
Foreground="{ThemeResource SystemBaseMediumColor}"
|
||||
Margin="0,4,0,0" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<!-- Main Content -->
|
||||
<Grid Grid.Row="1">
|
||||
|
||||
<!-- Loading State -->
|
||||
<StackPanel Visibility="{Binding IsLoading}"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center"
|
||||
Padding="32"
|
||||
Spacing="16">
|
||||
<ProgressRing IsActive="True"
|
||||
IsIndeterminate="True"
|
||||
Height="64"
|
||||
Width="64"
|
||||
Foreground="{ThemeResource SystemAccentColor}" />
|
||||
<TextBlock Text="Loading machine details..."
|
||||
FontSize="14"
|
||||
TextAlignment="Center"
|
||||
Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- Error State -->
|
||||
<StackPanel Visibility="{Binding HasError}"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center"
|
||||
Padding="24"
|
||||
Spacing="16"
|
||||
MaxWidth="400">
|
||||
<InfoBar IsOpen="True"
|
||||
Severity="Error"
|
||||
Title="Unable to Load Machine"
|
||||
Message="{Binding ErrorMessage}"
|
||||
IsClosable="False" />
|
||||
<Button Content="Retry"
|
||||
Command="{Binding LoadData}"
|
||||
HorizontalAlignment="Center"
|
||||
Style="{ThemeResource AccentButtonStyle}" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- Machine Details -->
|
||||
<ScrollViewer Visibility="{Binding IsDataLoaded}"
|
||||
VerticalScrollBarVisibility="Auto"
|
||||
HorizontalScrollBarVisibility="Disabled">
|
||||
<StackPanel Padding="16"
|
||||
Spacing="24">
|
||||
|
||||
<!-- Prototype Badge -->
|
||||
<StackPanel Visibility="{Binding IsPrototype}">
|
||||
<Border Background="{ThemeResource WarningFillColorTertiaryBrush}"
|
||||
BorderBrush="{ThemeResource WarningBorderColorDefaultBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="8"
|
||||
Padding="16,12">
|
||||
<TextBlock Text="PROTOTYPE"
|
||||
FontSize="14"
|
||||
FontWeight="Bold"
|
||||
Foreground="{ThemeResource WarningForegroundColorDefaultBrush}"
|
||||
TextAlignment="Center" />
|
||||
</Border>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Introduction Date -->
|
||||
<StackPanel Visibility="{Binding ShowIntroductionDate}"
|
||||
Spacing="8">
|
||||
<TextBlock Text="Introduction Date"
|
||||
FontSize="12"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||
<Border Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="8"
|
||||
Padding="16,12">
|
||||
<TextBlock Text="{Binding IntroductionDateDisplay}"
|
||||
FontSize="16"
|
||||
Foreground="{ThemeResource TextControlForeground}" />
|
||||
</Border>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Family and Model -->
|
||||
<Grid Visibility="{Binding ShowFamilyOrModel}"
|
||||
ColumnSpacing="16">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- Family -->
|
||||
<StackPanel Grid.Column="0"
|
||||
Visibility="{Binding ShowFamily}"
|
||||
Spacing="8">
|
||||
<TextBlock Text="Family"
|
||||
FontSize="12"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||
<Border Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="8"
|
||||
Padding="16,12">
|
||||
<TextBlock Text="{Binding FamilyName}"
|
||||
FontSize="14"
|
||||
Foreground="{ThemeResource TextControlForeground}"
|
||||
TextTrimming="CharacterEllipsis" />
|
||||
</Border>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Model -->
|
||||
<StackPanel Grid.Column="1"
|
||||
Visibility="{Binding ShowModel}"
|
||||
Spacing="8">
|
||||
<TextBlock Text="Model"
|
||||
FontSize="12"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||
<Border Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="8"
|
||||
Padding="16,12">
|
||||
<TextBlock Text="{Binding ModelName}"
|
||||
FontSize="14"
|
||||
Foreground="{ThemeResource TextControlForeground}"
|
||||
TextTrimming="CharacterEllipsis" />
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<!-- Processors Section -->
|
||||
<StackPanel Visibility="{Binding ShowProcessors}"
|
||||
Spacing="12">
|
||||
<TextBlock Text="Processors"
|
||||
FontSize="14"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{ThemeResource TextControlForeground}" />
|
||||
<ItemsControl ItemsSource="{Binding Processors}"
|
||||
HorizontalAlignment="Stretch">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Orientation="Vertical"
|
||||
Spacing="8" />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Border Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="8"
|
||||
Padding="16,12">
|
||||
<StackPanel Spacing="8">
|
||||
<TextBlock Text="{Binding DisplayName}"
|
||||
FontSize="14"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{ThemeResource TextControlForeground}" />
|
||||
<TextBlock Text="{Binding Manufacturer}"
|
||||
FontSize="12"
|
||||
Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||
<TextBlock Text="{Binding DetailsText}"
|
||||
FontSize="12"
|
||||
Foreground="{ThemeResource SystemBaseMediumColor}"
|
||||
TextWrapping="Wrap"
|
||||
Visibility="{Binding HasDetails}" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Memory Section -->
|
||||
<StackPanel Visibility="{Binding ShowMemory}"
|
||||
Spacing="12">
|
||||
<TextBlock Text="Memory"
|
||||
FontSize="14"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{ThemeResource TextControlForeground}" />
|
||||
<ItemsControl ItemsSource="{Binding Memory}"
|
||||
HorizontalAlignment="Stretch">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Orientation="Vertical"
|
||||
Spacing="8" />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Border Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="8"
|
||||
Padding="16,12">
|
||||
<StackPanel Spacing="6">
|
||||
<TextBlock Text="{Binding SizeDisplay}"
|
||||
FontSize="14"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{ThemeResource TextControlForeground}" />
|
||||
<TextBlock Text="{Binding TypeDisplay}"
|
||||
FontSize="12"
|
||||
Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</StackPanel>
|
||||
|
||||
<!-- GPUs Section -->
|
||||
<StackPanel Visibility="{Binding ShowGpus}"
|
||||
Spacing="12">
|
||||
<TextBlock Text="Graphics Processing Units"
|
||||
FontSize="14"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{ThemeResource TextControlForeground}" />
|
||||
<ItemsControl ItemsSource="{Binding Gpus}"
|
||||
HorizontalAlignment="Stretch">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Orientation="Vertical"
|
||||
Spacing="8" />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Border Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="8"
|
||||
Padding="16,12">
|
||||
<StackPanel Spacing="8">
|
||||
<TextBlock Text="{Binding DisplayName}"
|
||||
FontSize="14"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{ThemeResource TextControlForeground}" />
|
||||
<TextBlock Text="{Binding Manufacturer}"
|
||||
FontSize="12"
|
||||
Foreground="{ThemeResource SystemBaseMediumColor}"
|
||||
Visibility="{Binding HasManufacturer}" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Sound Synthesizers Section -->
|
||||
<StackPanel Visibility="{Binding ShowSoundSynthesizers}"
|
||||
Spacing="12">
|
||||
<TextBlock Text="Sound Synthesizers"
|
||||
FontSize="14"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{ThemeResource TextControlForeground}" />
|
||||
<ItemsControl ItemsSource="{Binding SoundSynthesizers}"
|
||||
HorizontalAlignment="Stretch">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Orientation="Vertical"
|
||||
Spacing="8" />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Border Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="8"
|
||||
Padding="16,12">
|
||||
<StackPanel Spacing="8">
|
||||
<TextBlock Text="{Binding DisplayName}"
|
||||
FontSize="14"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{ThemeResource TextControlForeground}" />
|
||||
<TextBlock Text="{Binding DetailsText}"
|
||||
FontSize="12"
|
||||
Foreground="{ThemeResource SystemBaseMediumColor}"
|
||||
TextWrapping="Wrap"
|
||||
Visibility="{Binding HasDetails}" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Storage Section -->
|
||||
<StackPanel Visibility="{Binding ShowStorage}"
|
||||
Spacing="12">
|
||||
<TextBlock Text="Storage"
|
||||
FontSize="14"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{ThemeResource TextControlForeground}" />
|
||||
<ItemsControl ItemsSource="{Binding Storage}"
|
||||
HorizontalAlignment="Stretch">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Orientation="Vertical"
|
||||
Spacing="8" />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Border Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="8"
|
||||
Padding="16,12">
|
||||
<StackPanel Spacing="6">
|
||||
<TextBlock Text="{Binding DisplayText}"
|
||||
FontSize="13"
|
||||
Foreground="{ThemeResource TextControlForeground}"
|
||||
TextWrapping="Wrap" />
|
||||
<TextBlock Text="{Binding TypeNote}"
|
||||
FontSize="11"
|
||||
Foreground="{ThemeResource SystemBaseMediumColor}"
|
||||
TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Bottom Spacing -->
|
||||
<Border Height="24" />
|
||||
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
|
||||
</Page>
|
||||
82
Marechai.App/Presentation/Views/MachineViewPage.xaml.cs
Normal file
82
Marechai.App/Presentation/Views/MachineViewPage.xaml.cs
Normal file
@@ -0,0 +1,82 @@
|
||||
/******************************************************************************
|
||||
// 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
|
||||
*******************************************************************************/
|
||||
|
||||
#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;
|
||||
|
||||
public sealed partial class MachineViewPage : Page
|
||||
{
|
||||
private object? _navigationSource;
|
||||
private int? _pendingMachineId;
|
||||
|
||||
public MachineViewPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContextChanged += MachineViewPage_DataContextChanged;
|
||||
}
|
||||
|
||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
base.OnNavigatedTo(e);
|
||||
|
||||
int? machineId = null;
|
||||
|
||||
// Handle both int and MachineViewNavigationParameter
|
||||
if(e.Parameter is int intId)
|
||||
machineId = intId;
|
||||
else if(e.Parameter is MachineViewNavigationParameter navParam)
|
||||
{
|
||||
machineId = navParam.MachineId;
|
||||
_navigationSource = navParam.NavigationSource;
|
||||
}
|
||||
|
||||
if(machineId.HasValue)
|
||||
{
|
||||
_pendingMachineId = machineId;
|
||||
|
||||
if(DataContext is MachineViewViewModel viewModel)
|
||||
{
|
||||
viewModel.SetNavigationSource(_navigationSource);
|
||||
_ = viewModel.LoadMachineAsync(machineId.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void MachineViewPage_DataContextChanged(FrameworkElement sender, DataContextChangedEventArgs args)
|
||||
{
|
||||
if(DataContext is MachineViewViewModel viewModel && _pendingMachineId.HasValue)
|
||||
{
|
||||
viewModel.SetNavigationSource(_navigationSource);
|
||||
_ = viewModel.LoadMachineAsync(_pendingMachineId.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
55
Marechai.App/Presentation/Views/MainPage.xaml
Normal file
55
Marechai.App/Presentation/Views/MainPage.xaml
Normal file
@@ -0,0 +1,55 @@
|
||||
<?xml version="1.0"
|
||||
encoding="utf-8"?>
|
||||
|
||||
<Page x:Class="Marechai.App.Presentation.Views.MainPage"
|
||||
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:uen="using:Uno.Extensions.Navigation.UI"
|
||||
xmlns:components="clr-namespace:Marechai.App.Presentation.Components"
|
||||
NavigationCacheMode="Required"
|
||||
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
|
||||
<Grid utu:SafeArea.Insets="VisibleBounds">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition x:Name="SidebarColumn"
|
||||
Width="280" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" /> <RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Sidebar -->
|
||||
<Grid x:Name="SidebarWrapper"
|
||||
Grid.Row="0"
|
||||
Grid.RowSpan="2"
|
||||
Grid.Column="0"
|
||||
Width="280"
|
||||
HorizontalAlignment="Left">
|
||||
<components:Sidebar x:Name="SidebarPanel"
|
||||
DataContext="{Binding}"
|
||||
VerticalAlignment="Stretch" />
|
||||
</Grid>
|
||||
|
||||
<!-- Header -->
|
||||
<utu:NavigationBar Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Content="{Binding Title}">
|
||||
<utu:NavigationBar.MainCommand>
|
||||
<AppBarButton Icon="GlobalNavigationButton"
|
||||
Command="{Binding ToggleSidebarCommand}"
|
||||
Label="Toggle Sidebar"
|
||||
AutomationProperties.Name="Toggle sidebar visibility" />
|
||||
</utu:NavigationBar.MainCommand>
|
||||
</utu:NavigationBar>
|
||||
|
||||
<!-- Content Region for Navigation -->
|
||||
<ContentControl Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
VerticalContentAlignment="Stretch"
|
||||
uen:Region.Attached="True"
|
||||
uen:Region.Name="Main" />
|
||||
</Grid>
|
||||
</Page>
|
||||
98
Marechai.App/Presentation/Views/MainPage.xaml.cs
Normal file
98
Marechai.App/Presentation/Views/MainPage.xaml.cs
Normal file
@@ -0,0 +1,98 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using Marechai.App.Presentation.ViewModels;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Marechai.App.Presentation.Views;
|
||||
|
||||
public sealed partial class MainPage : Page
|
||||
{
|
||||
private PropertyChangedEventHandler _sidebarPropertyChangedHandler;
|
||||
|
||||
public MainPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContextChanged += MainPage_DataContextChanged;
|
||||
Loaded += MainPage_Loaded;
|
||||
}
|
||||
|
||||
private void MainPage_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if(DataContext is not MainViewModel viewModel) return;
|
||||
|
||||
SidebarWrapper.Width = viewModel.IsSidebarOpen ? 280 : 60;
|
||||
|
||||
if(_sidebarPropertyChangedHandler != null) return;
|
||||
|
||||
_sidebarPropertyChangedHandler = (_, propArgs) =>
|
||||
{
|
||||
if(propArgs.PropertyName != nameof(MainViewModel.IsSidebarOpen)) return;
|
||||
|
||||
AnimateSidebarWidth(((MainViewModel)DataContext).IsSidebarOpen);
|
||||
};
|
||||
|
||||
((INotifyPropertyChanged)viewModel).PropertyChanged += _sidebarPropertyChangedHandler;
|
||||
}
|
||||
|
||||
void AnimateSidebarWidth(bool isOpen)
|
||||
{
|
||||
double start = SidebarColumn.Width.Value;
|
||||
double end = isOpen ? 280 : 60;
|
||||
|
||||
if(Math.Abs(start - end) < 0.1) return;
|
||||
|
||||
// If expanding, show content immediately
|
||||
if(isOpen && DataContext is MainViewModel vm) vm.SidebarContentVisible = true;
|
||||
|
||||
const int durationMs = 250;
|
||||
const int fps = 60;
|
||||
var steps = (int)(durationMs / (1000.0 / fps));
|
||||
var currentStep = 0;
|
||||
|
||||
var timer = new DispatcherTimer
|
||||
{
|
||||
Interval = TimeSpan.FromMilliseconds(1000.0 / fps)
|
||||
};
|
||||
|
||||
timer.Tick += (_, _) =>
|
||||
{
|
||||
currentStep++;
|
||||
double t = (double)currentStep / steps;
|
||||
|
||||
// Ease in-out cubic
|
||||
double eased = t < 0.5 ? 4 * t * t * t : 1 - Math.Pow(-2 * t + 2, 3) / 2;
|
||||
double value = start + (end - start) * eased;
|
||||
SidebarColumn.Width = new GridLength(value, GridUnitType.Pixel);
|
||||
SidebarWrapper.Width = value;
|
||||
|
||||
if(currentStep >= steps)
|
||||
{
|
||||
SidebarColumn.Width = new GridLength(end, GridUnitType.Pixel);
|
||||
SidebarWrapper.Width = end;
|
||||
timer.Stop();
|
||||
|
||||
// After collapse animation completes, hide sidebar content
|
||||
if(!isOpen && DataContext is MainViewModel vm) vm.SidebarContentVisible = false;
|
||||
}
|
||||
};
|
||||
|
||||
timer.Start();
|
||||
}
|
||||
|
||||
private void MainPage_DataContextChanged(FrameworkElement sender, DataContextChangedEventArgs args)
|
||||
{
|
||||
if(args.NewValue is MainViewModel vm && _sidebarPropertyChangedHandler == null)
|
||||
{
|
||||
SidebarWrapper.Width = vm.IsSidebarOpen ? 280 : 60;
|
||||
|
||||
_sidebarPropertyChangedHandler = (_, propArgs) =>
|
||||
{
|
||||
if(propArgs.PropertyName != nameof(MainViewModel.IsSidebarOpen)) return;
|
||||
AnimateSidebarWidth(vm.IsSidebarOpen);
|
||||
};
|
||||
|
||||
((INotifyPropertyChanged)vm).PropertyChanged += _sidebarPropertyChangedHandler;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0"
|
||||
<?xml version="1.0"
|
||||
encoding="utf-8"?>
|
||||
|
||||
<Page x:Class="Marechai.App.Presentation.MainPage"
|
||||
<Page x:Class="Marechai.App.Presentation.Views.NewsPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:utu="using:Uno.Toolkit.UI"
|
||||
@@ -9,16 +9,7 @@
|
||||
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
|
||||
<Grid utu:SafeArea.Insets="VisibleBounds">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" /> <RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Header -->
|
||||
<utu:NavigationBar Content="{Binding Title}" />
|
||||
|
||||
<!-- Refresh Container with Pull-to-Refresh -->
|
||||
<RefreshContainer Grid.Row="1"
|
||||
x:Name="RefreshContainer"
|
||||
<RefreshContainer x:Name="RefreshContainer"
|
||||
RefreshRequested="RefreshContainer_RefreshRequested">
|
||||
<ScrollViewer>
|
||||
<Grid Padding="16">
|
||||
@@ -42,7 +33,7 @@
|
||||
|
||||
<!-- Loading State -->
|
||||
<StackPanel Grid.Row="2"
|
||||
Visibility="{Binding NewsViewModel.IsLoading}"
|
||||
Visibility="{Binding IsLoading}"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center"
|
||||
Padding="32"
|
||||
@@ -60,62 +51,69 @@
|
||||
|
||||
<!-- Error State -->
|
||||
<StackPanel Grid.Row="2"
|
||||
Visibility="{Binding NewsViewModel.HasError}"
|
||||
Visibility="{Binding HasError}"
|
||||
VerticalAlignment="Center"
|
||||
Spacing="16"
|
||||
Padding="32">
|
||||
<InfoBar IsOpen="True"
|
||||
Severity="Error"
|
||||
Title="Unable to Load News"
|
||||
Message="{Binding NewsViewModel.ErrorMessage}"
|
||||
Message="{Binding ErrorMessage}"
|
||||
IsClosable="False" />
|
||||
<Button Content="Retry"
|
||||
Command="{Binding NewsViewModel.LoadNews}"
|
||||
Command="{Binding LoadNews}"
|
||||
HorizontalAlignment="Center"
|
||||
Style="{ThemeResource AccentButtonStyle}" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- News Feed -->
|
||||
<ItemsControl Grid.Row="2"
|
||||
ItemsSource="{Binding NewsViewModel.NewsList}">
|
||||
ItemsSource="{Binding NewsList}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Border Margin="0,0,0,12"
|
||||
CornerRadius="8"
|
||||
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
|
||||
BorderThickness="1"
|
||||
Padding="16">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Button Margin="0,0,0,12"
|
||||
Padding="0"
|
||||
Background="Transparent"
|
||||
BorderThickness="0"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
Command="{Binding NavigateToItemCommand}"
|
||||
CommandParameter="{Binding News}">
|
||||
<Border CornerRadius="8"
|
||||
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
|
||||
BorderThickness="1"
|
||||
Padding="16">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Date -->
|
||||
<TextBlock Grid.Row="0"
|
||||
Text="{Binding News.Timestamp}"
|
||||
FontSize="12"
|
||||
Foreground="{ThemeResource SystemBaseMediumColor}"
|
||||
Margin="0,0,0,12" />
|
||||
<!-- Date -->
|
||||
<TextBlock Grid.Row="0"
|
||||
Text="{Binding News.Timestamp}"
|
||||
FontSize="12"
|
||||
Foreground="{ThemeResource SystemBaseMediumColor}"
|
||||
Margin="0,0,0,12" />
|
||||
|
||||
<!-- News Title/Text (Localized) -->
|
||||
<TextBlock Grid.Row="1"
|
||||
Text="{Binding DisplayText}"
|
||||
FontSize="16"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{ThemeResource SystemBaseHighColor}"
|
||||
TextWrapping="Wrap"
|
||||
Margin="0,0,0,12" />
|
||||
<!-- News Title/Text (Localized) -->
|
||||
<TextBlock Grid.Row="1"
|
||||
Text="{Binding DisplayText}"
|
||||
FontSize="16"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{ThemeResource SystemBaseHighColor}"
|
||||
TextWrapping="Wrap"
|
||||
Margin="0,0,0,12" />
|
||||
|
||||
<!-- Item Name Link -->
|
||||
<HyperlinkButton Grid.Row="2"
|
||||
Content="{Binding News.ItemName}"
|
||||
FontSize="14"
|
||||
Padding="0,4,0,4"
|
||||
Foreground="{ThemeResource SystemAccentColor}" />
|
||||
</Grid>
|
||||
</Border>
|
||||
<!-- Item Name -->
|
||||
<TextBlock Grid.Row="2"
|
||||
Text="{Binding News.ItemName}"
|
||||
FontSize="14"
|
||||
Foreground="{ThemeResource SystemAccentColor}" />
|
||||
</Grid>
|
||||
</Border>
|
||||
</Button>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
<ItemsControl.ItemsPanel>
|
||||
73
Marechai.App/Presentation/Views/NewsPage.xaml.cs
Normal file
73
Marechai.App/Presentation/Views/NewsPage.xaml.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
using System;
|
||||
using Windows.Foundation;
|
||||
using Marechai.App.Presentation.ViewModels;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
|
||||
namespace Marechai.App.Presentation.Views;
|
||||
|
||||
public sealed partial class NewsPage : Page
|
||||
{
|
||||
private bool _initialNewsLoaded;
|
||||
|
||||
public NewsPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContextChanged += NewsPage_DataContextChanged;
|
||||
Loaded += NewsPage_Loaded;
|
||||
}
|
||||
|
||||
private void NewsPage_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if(_initialNewsLoaded) return;
|
||||
|
||||
if(DataContext is NewsViewModel viewModel)
|
||||
{
|
||||
_initialNewsLoaded = true;
|
||||
_ = viewModel.LoadNews.ExecuteAsync(null);
|
||||
DataContextChanged -= NewsPage_DataContextChanged;
|
||||
}
|
||||
}
|
||||
|
||||
private void NewsPage_DataContextChanged(FrameworkElement sender, DataContextChangedEventArgs args)
|
||||
{
|
||||
if(_initialNewsLoaded) return;
|
||||
|
||||
if(args.NewValue is NewsViewModel viewModel)
|
||||
{
|
||||
_initialNewsLoaded = true;
|
||||
_ = viewModel.LoadNews.ExecuteAsync(null);
|
||||
DataContextChanged -= NewsPage_DataContextChanged;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
base.OnNavigatedTo(e);
|
||||
|
||||
if(_initialNewsLoaded) return;
|
||||
|
||||
if(DataContext is NewsViewModel viewModel)
|
||||
{
|
||||
_initialNewsLoaded = true;
|
||||
_ = viewModel.LoadNews.ExecuteAsync(null);
|
||||
DataContextChanged -= NewsPage_DataContextChanged;
|
||||
}
|
||||
}
|
||||
|
||||
private async void RefreshContainer_RefreshRequested(RefreshContainer sender, RefreshRequestedEventArgs args)
|
||||
{
|
||||
// Handle pull-to-refresh
|
||||
using Deferral deferral = args.GetDeferral();
|
||||
|
||||
try
|
||||
{
|
||||
if(DataContext is NewsViewModel viewModel) await viewModel.LoadNews.ExecuteAsync(null);
|
||||
}
|
||||
catch(Exception)
|
||||
{
|
||||
// Swallow to avoid process crash; NewsViewModel already logs errors.
|
||||
}
|
||||
}
|
||||
}
|
||||
22
Marechai.App/Presentation/Views/SecondPage.xaml
Normal file
22
Marechai.App/Presentation/Views/SecondPage.xaml
Normal file
@@ -0,0 +1,22 @@
|
||||
<Page x:Class="Marechai.App.Presentation.Views.SecondPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:utu="using:Uno.Toolkit.UI"
|
||||
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
|
||||
<Grid utu:SafeArea.Insets="VisibleBounds">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" /> <RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<utu:NavigationBar Content="Second Page" />
|
||||
<StackPanel Grid.Row="1"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center">
|
||||
<TextBlock Text="{Binding Entity.Name}"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Margin="8" />
|
||||
</StackPanel>
|
||||
|
||||
</Grid>
|
||||
</Page>
|
||||
@@ -1,11 +1,11 @@
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Marechai.App.Presentation;
|
||||
namespace Marechai.App.Presentation.Views;
|
||||
|
||||
public sealed partial class SecondPage : Page
|
||||
{
|
||||
public SecondPage()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
34
Marechai.App/Presentation/Views/Shell.xaml
Normal file
34
Marechai.App/Presentation/Views/Shell.xaml
Normal file
@@ -0,0 +1,34 @@
|
||||
<UserControl x:Class="Marechai.App.Presentation.Views.Shell"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:utu="using:Uno.Toolkit.UI"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="300"
|
||||
d:DesignWidth="400">
|
||||
<Border Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
<utu:ExtendedSplashScreen x:Name="Splash"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
VerticalContentAlignment="Stretch">
|
||||
<utu:ExtendedSplashScreen.LoadingContentTemplate>
|
||||
<DataTemplate>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="2*" /> <RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<ProgressRing IsActive="True"
|
||||
Grid.Row="1"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center"
|
||||
Height="100"
|
||||
Width="100" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</utu:ExtendedSplashScreen.LoadingContentTemplate>
|
||||
</utu:ExtendedSplashScreen>
|
||||
</Border>
|
||||
</UserControl>
|
||||
@@ -1,14 +1,14 @@
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Uno.Extensions.Hosting;
|
||||
|
||||
namespace Marechai.App.Presentation;
|
||||
namespace Marechai.App.Presentation.Views;
|
||||
|
||||
public sealed partial class Shell : UserControl, IContentControlProvider
|
||||
{
|
||||
public Shell()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public ContentControl ContentControl => Splash;
|
||||
}
|
||||
}
|
||||
@@ -3,12 +3,9 @@
|
||||
using Marechai.App.Auth;
|
||||
using Marechai.App.Books;
|
||||
using Marechai.App.BrowserTests;
|
||||
using Marechai.App.ByLetter;
|
||||
using Marechai.App.ByYear;
|
||||
using Marechai.App.Companies;
|
||||
using Marechai.App.Computers;
|
||||
using Marechai.App.Consoles;
|
||||
using Marechai.App.Count;
|
||||
using Marechai.App.Countries;
|
||||
using Marechai.App.Currencies;
|
||||
using Marechai.App.Documents;
|
||||
@@ -25,10 +22,8 @@ using Marechai.App.Machines;
|
||||
using Marechai.App.Magazines;
|
||||
using Marechai.App.MagazinesByMachine;
|
||||
using Marechai.App.MagazinesByMachineFamily;
|
||||
using Marechai.App.MaximumYear;
|
||||
using Marechai.App.Medias;
|
||||
using Marechai.App.MemoriesByMachine;
|
||||
using Marechai.App.MinimumYear;
|
||||
using Marechai.App.News;
|
||||
using Marechai.App.People;
|
||||
using Marechai.App.PeopleByBook;
|
||||
@@ -79,16 +74,6 @@ namespace Marechai.App
|
||||
{
|
||||
get => new global::Marechai.App.BrowserTests.BrowserTestsRequestBuilder(PathParameters, RequestAdapter);
|
||||
}
|
||||
/// <summary>The byLetter property</summary>
|
||||
public global::Marechai.App.ByLetter.ByLetterRequestBuilder ByLetter
|
||||
{
|
||||
get => new global::Marechai.App.ByLetter.ByLetterRequestBuilder(PathParameters, RequestAdapter);
|
||||
}
|
||||
/// <summary>The byYear property</summary>
|
||||
public global::Marechai.App.ByYear.ByYearRequestBuilder ByYear
|
||||
{
|
||||
get => new global::Marechai.App.ByYear.ByYearRequestBuilder(PathParameters, RequestAdapter);
|
||||
}
|
||||
/// <summary>The companies property</summary>
|
||||
public global::Marechai.App.Companies.CompaniesRequestBuilder Companies
|
||||
{
|
||||
@@ -104,11 +89,6 @@ namespace Marechai.App
|
||||
{
|
||||
get => new global::Marechai.App.Consoles.ConsolesRequestBuilder(PathParameters, RequestAdapter);
|
||||
}
|
||||
/// <summary>The count property</summary>
|
||||
public global::Marechai.App.Count.CountRequestBuilder Count
|
||||
{
|
||||
get => new global::Marechai.App.Count.CountRequestBuilder(PathParameters, RequestAdapter);
|
||||
}
|
||||
/// <summary>The countries property</summary>
|
||||
public global::Marechai.App.Countries.CountriesRequestBuilder Countries
|
||||
{
|
||||
@@ -189,11 +169,6 @@ namespace Marechai.App
|
||||
{
|
||||
get => new global::Marechai.App.MagazinesByMachineFamily.MagazinesByMachineFamilyRequestBuilder(PathParameters, RequestAdapter);
|
||||
}
|
||||
/// <summary>The maximumYear property</summary>
|
||||
public global::Marechai.App.MaximumYear.MaximumYearRequestBuilder MaximumYear
|
||||
{
|
||||
get => new global::Marechai.App.MaximumYear.MaximumYearRequestBuilder(PathParameters, RequestAdapter);
|
||||
}
|
||||
/// <summary>The medias property</summary>
|
||||
public global::Marechai.App.Medias.MediasRequestBuilder Medias
|
||||
{
|
||||
@@ -204,11 +179,6 @@ namespace Marechai.App
|
||||
{
|
||||
get => new global::Marechai.App.MemoriesByMachine.MemoriesByMachineRequestBuilder(PathParameters, RequestAdapter);
|
||||
}
|
||||
/// <summary>The minimumYear property</summary>
|
||||
public global::Marechai.App.MinimumYear.MinimumYearRequestBuilder MinimumYear
|
||||
{
|
||||
get => new global::Marechai.App.MinimumYear.MinimumYearRequestBuilder(PathParameters, RequestAdapter);
|
||||
}
|
||||
/// <summary>The news property</summary>
|
||||
public global::Marechai.App.News.NewsRequestBuilder News
|
||||
{
|
||||
@@ -309,7 +279,7 @@ namespace Marechai.App
|
||||
ApiClientBuilder.RegisterDefaultDeserializer<FormParseNodeFactory>();
|
||||
if (string.IsNullOrEmpty(RequestAdapter.BaseUrl))
|
||||
{
|
||||
RequestAdapter.BaseUrl = "http://localhost:5023";
|
||||
RequestAdapter.BaseUrl = "https://localhost:7163";
|
||||
}
|
||||
PathParameters.TryAdd("baseurl", RequestAdapter.BaseUrl);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
// <auto-generated/>
|
||||
#pragma warning disable CS0618
|
||||
using Marechai.App.Computers.ByLetter.Item;
|
||||
using Microsoft.Kiota.Abstractions.Extensions;
|
||||
using Microsoft.Kiota.Abstractions;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using System;
|
||||
namespace Marechai.App.Computers.ByLetter
|
||||
{
|
||||
/// <summary>
|
||||
/// Builds and executes requests for operations under \computers\by-letter
|
||||
/// </summary>
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
|
||||
public partial class ByLetterRequestBuilder : BaseRequestBuilder
|
||||
{
|
||||
/// <summary>Gets an item from the Marechai.App.computers.byLetter.item collection</summary>
|
||||
/// <param name="position">Unique identifier of the item</param>
|
||||
/// <returns>A <see cref="global::Marechai.App.Computers.ByLetter.Item.WithCItemRequestBuilder"/></returns>
|
||||
public global::Marechai.App.Computers.ByLetter.Item.WithCItemRequestBuilder this[string position]
|
||||
{
|
||||
get
|
||||
{
|
||||
var urlTplParams = new Dictionary<string, object>(PathParameters);
|
||||
urlTplParams.Add("c", position);
|
||||
return new global::Marechai.App.Computers.ByLetter.Item.WithCItemRequestBuilder(urlTplParams, RequestAdapter);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Instantiates a new <see cref="global::Marechai.App.Computers.ByLetter.ByLetterRequestBuilder"/> and sets the default values.
|
||||
/// </summary>
|
||||
/// <param name="pathParameters">Path parameters for the request</param>
|
||||
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
|
||||
public ByLetterRequestBuilder(Dictionary<string, object> pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/computers/by-letter", pathParameters)
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// Instantiates a new <see cref="global::Marechai.App.Computers.ByLetter.ByLetterRequestBuilder"/> and sets the default values.
|
||||
/// </summary>
|
||||
/// <param name="rawUrl">The raw URL to use for the request builder.</param>
|
||||
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
|
||||
public ByLetterRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/computers/by-letter", rawUrl)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma warning restore CS0618
|
||||
@@ -0,0 +1,92 @@
|
||||
// <auto-generated/>
|
||||
#pragma warning disable CS0618
|
||||
using Marechai.App.Models;
|
||||
using Microsoft.Kiota.Abstractions.Extensions;
|
||||
using Microsoft.Kiota.Abstractions.Serialization;
|
||||
using Microsoft.Kiota.Abstractions;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
using System;
|
||||
namespace Marechai.App.Computers.ByLetter.Item
|
||||
{
|
||||
/// <summary>
|
||||
/// Builds and executes requests for operations under \computers\by-letter\{c}
|
||||
/// </summary>
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
|
||||
public partial class WithCItemRequestBuilder : BaseRequestBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// Instantiates a new <see cref="global::Marechai.App.Computers.ByLetter.Item.WithCItemRequestBuilder"/> and sets the default values.
|
||||
/// </summary>
|
||||
/// <param name="pathParameters">Path parameters for the request</param>
|
||||
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
|
||||
public WithCItemRequestBuilder(Dictionary<string, object> pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/computers/by-letter/{c}", pathParameters)
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// Instantiates a new <see cref="global::Marechai.App.Computers.ByLetter.Item.WithCItemRequestBuilder"/> and sets the default values.
|
||||
/// </summary>
|
||||
/// <param name="rawUrl">The raw URL to use for the request builder.</param>
|
||||
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
|
||||
public WithCItemRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/computers/by-letter/{c}", rawUrl)
|
||||
{
|
||||
}
|
||||
/// <returns>A List<global::Marechai.App.Models.MachineDto></returns>
|
||||
/// <param name="cancellationToken">Cancellation token to use when cancelling requests</param>
|
||||
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
|
||||
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 400 status code</exception>
|
||||
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
|
||||
#nullable enable
|
||||
public async Task<List<global::Marechai.App.Models.MachineDto>?> GetAsync(Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default, CancellationToken cancellationToken = default)
|
||||
{
|
||||
#nullable restore
|
||||
#else
|
||||
public async Task<List<global::Marechai.App.Models.MachineDto>> GetAsync(Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default, CancellationToken cancellationToken = default)
|
||||
{
|
||||
#endif
|
||||
var requestInfo = ToGetRequestInformation(requestConfiguration);
|
||||
var errorMapping = new Dictionary<string, ParsableFactory<IParsable>>
|
||||
{
|
||||
{ "400", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
|
||||
};
|
||||
var collectionResult = await RequestAdapter.SendCollectionAsync<global::Marechai.App.Models.MachineDto>(requestInfo, global::Marechai.App.Models.MachineDto.CreateFromDiscriminatorValue, errorMapping, cancellationToken).ConfigureAwait(false);
|
||||
return collectionResult?.AsList();
|
||||
}
|
||||
/// <returns>A <see cref="RequestInformation"/></returns>
|
||||
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
|
||||
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
|
||||
#nullable enable
|
||||
public RequestInformation ToGetRequestInformation(Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default)
|
||||
{
|
||||
#nullable restore
|
||||
#else
|
||||
public RequestInformation ToGetRequestInformation(Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default)
|
||||
{
|
||||
#endif
|
||||
var requestInfo = new RequestInformation(Method.GET, UrlTemplate, PathParameters);
|
||||
requestInfo.Configure(requestConfiguration);
|
||||
requestInfo.Headers.TryAdd("Accept", "text/plain;q=0.9");
|
||||
return requestInfo;
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns a request builder with the provided arbitrary URL. Using this method means any other path or query parameters are ignored.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="global::Marechai.App.Computers.ByLetter.Item.WithCItemRequestBuilder"/></returns>
|
||||
/// <param name="rawUrl">The raw URL to use for the request builder.</param>
|
||||
public global::Marechai.App.Computers.ByLetter.Item.WithCItemRequestBuilder WithUrl(string rawUrl)
|
||||
{
|
||||
return new global::Marechai.App.Computers.ByLetter.Item.WithCItemRequestBuilder(rawUrl, RequestAdapter);
|
||||
}
|
||||
/// <summary>
|
||||
/// Configuration for the request such as headers, query parameters, and middleware options.
|
||||
/// </summary>
|
||||
[Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
|
||||
public partial class WithCItemRequestBuilderGetRequestConfiguration : RequestConfiguration<DefaultQueryParameters>
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma warning restore CS0618
|
||||
@@ -0,0 +1,61 @@
|
||||
// <auto-generated/>
|
||||
#pragma warning disable CS0618
|
||||
using Marechai.App.Computers.ByYear.Item;
|
||||
using Microsoft.Kiota.Abstractions.Extensions;
|
||||
using Microsoft.Kiota.Abstractions;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using System;
|
||||
namespace Marechai.App.Computers.ByYear
|
||||
{
|
||||
/// <summary>
|
||||
/// Builds and executes requests for operations under \computers\by-year
|
||||
/// </summary>
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
|
||||
public partial class ByYearRequestBuilder : BaseRequestBuilder
|
||||
{
|
||||
/// <summary>Gets an item from the Marechai.App.computers.byYear.item collection</summary>
|
||||
/// <param name="position">Unique identifier of the item</param>
|
||||
/// <returns>A <see cref="global::Marechai.App.Computers.ByYear.Item.WithYearItemRequestBuilder"/></returns>
|
||||
public global::Marechai.App.Computers.ByYear.Item.WithYearItemRequestBuilder this[int position]
|
||||
{
|
||||
get
|
||||
{
|
||||
var urlTplParams = new Dictionary<string, object>(PathParameters);
|
||||
urlTplParams.Add("year", position);
|
||||
return new global::Marechai.App.Computers.ByYear.Item.WithYearItemRequestBuilder(urlTplParams, RequestAdapter);
|
||||
}
|
||||
}
|
||||
/// <summary>Gets an item from the Marechai.App.computers.byYear.item collection</summary>
|
||||
/// <param name="position">Unique identifier of the item</param>
|
||||
/// <returns>A <see cref="global::Marechai.App.Computers.ByYear.Item.WithYearItemRequestBuilder"/></returns>
|
||||
[Obsolete("This indexer is deprecated and will be removed in the next major version. Use the one with the typed parameter instead.")]
|
||||
public global::Marechai.App.Computers.ByYear.Item.WithYearItemRequestBuilder this[string position]
|
||||
{
|
||||
get
|
||||
{
|
||||
var urlTplParams = new Dictionary<string, object>(PathParameters);
|
||||
if (!string.IsNullOrWhiteSpace(position)) urlTplParams.Add("year", position);
|
||||
return new global::Marechai.App.Computers.ByYear.Item.WithYearItemRequestBuilder(urlTplParams, RequestAdapter);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Instantiates a new <see cref="global::Marechai.App.Computers.ByYear.ByYearRequestBuilder"/> and sets the default values.
|
||||
/// </summary>
|
||||
/// <param name="pathParameters">Path parameters for the request</param>
|
||||
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
|
||||
public ByYearRequestBuilder(Dictionary<string, object> pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/computers/by-year", pathParameters)
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// Instantiates a new <see cref="global::Marechai.App.Computers.ByYear.ByYearRequestBuilder"/> and sets the default values.
|
||||
/// </summary>
|
||||
/// <param name="rawUrl">The raw URL to use for the request builder.</param>
|
||||
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
|
||||
public ByYearRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/computers/by-year", rawUrl)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma warning restore CS0618
|
||||
@@ -0,0 +1,92 @@
|
||||
// <auto-generated/>
|
||||
#pragma warning disable CS0618
|
||||
using Marechai.App.Models;
|
||||
using Microsoft.Kiota.Abstractions.Extensions;
|
||||
using Microsoft.Kiota.Abstractions.Serialization;
|
||||
using Microsoft.Kiota.Abstractions;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
using System;
|
||||
namespace Marechai.App.Computers.ByYear.Item
|
||||
{
|
||||
/// <summary>
|
||||
/// Builds and executes requests for operations under \computers\by-year\{year}
|
||||
/// </summary>
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
|
||||
public partial class WithYearItemRequestBuilder : BaseRequestBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// Instantiates a new <see cref="global::Marechai.App.Computers.ByYear.Item.WithYearItemRequestBuilder"/> and sets the default values.
|
||||
/// </summary>
|
||||
/// <param name="pathParameters">Path parameters for the request</param>
|
||||
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
|
||||
public WithYearItemRequestBuilder(Dictionary<string, object> pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/computers/by-year/{year}", pathParameters)
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// Instantiates a new <see cref="global::Marechai.App.Computers.ByYear.Item.WithYearItemRequestBuilder"/> and sets the default values.
|
||||
/// </summary>
|
||||
/// <param name="rawUrl">The raw URL to use for the request builder.</param>
|
||||
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
|
||||
public WithYearItemRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/computers/by-year/{year}", rawUrl)
|
||||
{
|
||||
}
|
||||
/// <returns>A List<global::Marechai.App.Models.MachineDto></returns>
|
||||
/// <param name="cancellationToken">Cancellation token to use when cancelling requests</param>
|
||||
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
|
||||
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 400 status code</exception>
|
||||
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
|
||||
#nullable enable
|
||||
public async Task<List<global::Marechai.App.Models.MachineDto>?> GetAsync(Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default, CancellationToken cancellationToken = default)
|
||||
{
|
||||
#nullable restore
|
||||
#else
|
||||
public async Task<List<global::Marechai.App.Models.MachineDto>> GetAsync(Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default, CancellationToken cancellationToken = default)
|
||||
{
|
||||
#endif
|
||||
var requestInfo = ToGetRequestInformation(requestConfiguration);
|
||||
var errorMapping = new Dictionary<string, ParsableFactory<IParsable>>
|
||||
{
|
||||
{ "400", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
|
||||
};
|
||||
var collectionResult = await RequestAdapter.SendCollectionAsync<global::Marechai.App.Models.MachineDto>(requestInfo, global::Marechai.App.Models.MachineDto.CreateFromDiscriminatorValue, errorMapping, cancellationToken).ConfigureAwait(false);
|
||||
return collectionResult?.AsList();
|
||||
}
|
||||
/// <returns>A <see cref="RequestInformation"/></returns>
|
||||
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
|
||||
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
|
||||
#nullable enable
|
||||
public RequestInformation ToGetRequestInformation(Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default)
|
||||
{
|
||||
#nullable restore
|
||||
#else
|
||||
public RequestInformation ToGetRequestInformation(Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default)
|
||||
{
|
||||
#endif
|
||||
var requestInfo = new RequestInformation(Method.GET, UrlTemplate, PathParameters);
|
||||
requestInfo.Configure(requestConfiguration);
|
||||
requestInfo.Headers.TryAdd("Accept", "text/plain;q=0.9");
|
||||
return requestInfo;
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns a request builder with the provided arbitrary URL. Using this method means any other path or query parameters are ignored.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="global::Marechai.App.Computers.ByYear.Item.WithYearItemRequestBuilder"/></returns>
|
||||
/// <param name="rawUrl">The raw URL to use for the request builder.</param>
|
||||
public global::Marechai.App.Computers.ByYear.Item.WithYearItemRequestBuilder WithUrl(string rawUrl)
|
||||
{
|
||||
return new global::Marechai.App.Computers.ByYear.Item.WithYearItemRequestBuilder(rawUrl, RequestAdapter);
|
||||
}
|
||||
/// <summary>
|
||||
/// Configuration for the request such as headers, query parameters, and middleware options.
|
||||
/// </summary>
|
||||
[Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
|
||||
public partial class WithYearItemRequestBuilderGetRequestConfiguration : RequestConfiguration<DefaultQueryParameters>
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma warning restore CS0618
|
||||
@@ -1,5 +1,10 @@
|
||||
// <auto-generated/>
|
||||
#pragma warning disable CS0618
|
||||
using Marechai.App.Computers.ByLetter;
|
||||
using Marechai.App.Computers.ByYear;
|
||||
using Marechai.App.Computers.Count;
|
||||
using Marechai.App.Computers.MaximumYear;
|
||||
using Marechai.App.Computers.MinimumYear;
|
||||
using Marechai.App.Models;
|
||||
using Microsoft.Kiota.Abstractions.Extensions;
|
||||
using Microsoft.Kiota.Abstractions.Serialization;
|
||||
@@ -17,6 +22,31 @@ namespace Marechai.App.Computers
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
|
||||
public partial class ComputersRequestBuilder : BaseRequestBuilder
|
||||
{
|
||||
/// <summary>The byLetter property</summary>
|
||||
public global::Marechai.App.Computers.ByLetter.ByLetterRequestBuilder ByLetter
|
||||
{
|
||||
get => new global::Marechai.App.Computers.ByLetter.ByLetterRequestBuilder(PathParameters, RequestAdapter);
|
||||
}
|
||||
/// <summary>The byYear property</summary>
|
||||
public global::Marechai.App.Computers.ByYear.ByYearRequestBuilder ByYear
|
||||
{
|
||||
get => new global::Marechai.App.Computers.ByYear.ByYearRequestBuilder(PathParameters, RequestAdapter);
|
||||
}
|
||||
/// <summary>The count property</summary>
|
||||
public global::Marechai.App.Computers.Count.CountRequestBuilder Count
|
||||
{
|
||||
get => new global::Marechai.App.Computers.Count.CountRequestBuilder(PathParameters, RequestAdapter);
|
||||
}
|
||||
/// <summary>The maximumYear property</summary>
|
||||
public global::Marechai.App.Computers.MaximumYear.MaximumYearRequestBuilder MaximumYear
|
||||
{
|
||||
get => new global::Marechai.App.Computers.MaximumYear.MaximumYearRequestBuilder(PathParameters, RequestAdapter);
|
||||
}
|
||||
/// <summary>The minimumYear property</summary>
|
||||
public global::Marechai.App.Computers.MinimumYear.MinimumYearRequestBuilder MinimumYear
|
||||
{
|
||||
get => new global::Marechai.App.Computers.MinimumYear.MinimumYearRequestBuilder(PathParameters, RequestAdapter);
|
||||
}
|
||||
/// <summary>
|
||||
/// Instantiates a new <see cref="global::Marechai.App.Computers.ComputersRequestBuilder"/> and sets the default values.
|
||||
/// </summary>
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
// <auto-generated/>
|
||||
#pragma warning disable CS0618
|
||||
using Marechai.App.Models;
|
||||
using Microsoft.Kiota.Abstractions.Extensions;
|
||||
using Microsoft.Kiota.Abstractions.Serialization;
|
||||
using Microsoft.Kiota.Abstractions;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
using System;
|
||||
namespace Marechai.App.Computers.Count
|
||||
{
|
||||
/// <summary>
|
||||
/// Builds and executes requests for operations under \computers\count
|
||||
/// </summary>
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
|
||||
public partial class CountRequestBuilder : BaseRequestBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// Instantiates a new <see cref="global::Marechai.App.Computers.Count.CountRequestBuilder"/> and sets the default values.
|
||||
/// </summary>
|
||||
/// <param name="pathParameters">Path parameters for the request</param>
|
||||
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
|
||||
public CountRequestBuilder(Dictionary<string, object> pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/computers/count", pathParameters)
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// Instantiates a new <see cref="global::Marechai.App.Computers.Count.CountRequestBuilder"/> and sets the default values.
|
||||
/// </summary>
|
||||
/// <param name="rawUrl">The raw URL to use for the request builder.</param>
|
||||
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
|
||||
public CountRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/computers/count", rawUrl)
|
||||
{
|
||||
}
|
||||
/// <returns>A <see cref="UntypedNode"/></returns>
|
||||
/// <param name="cancellationToken">Cancellation token to use when cancelling requests</param>
|
||||
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
|
||||
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 400 status code</exception>
|
||||
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
|
||||
#nullable enable
|
||||
public async Task<UntypedNode?> GetAsync(Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default, CancellationToken cancellationToken = default)
|
||||
{
|
||||
#nullable restore
|
||||
#else
|
||||
public async Task<UntypedNode> GetAsync(Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default, CancellationToken cancellationToken = default)
|
||||
{
|
||||
#endif
|
||||
var requestInfo = ToGetRequestInformation(requestConfiguration);
|
||||
var errorMapping = new Dictionary<string, ParsableFactory<IParsable>>
|
||||
{
|
||||
{ "400", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
|
||||
};
|
||||
return await RequestAdapter.SendAsync<UntypedNode>(requestInfo, UntypedNode.CreateFromDiscriminatorValue, errorMapping, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
/// <returns>A <see cref="RequestInformation"/></returns>
|
||||
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
|
||||
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
|
||||
#nullable enable
|
||||
public RequestInformation ToGetRequestInformation(Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default)
|
||||
{
|
||||
#nullable restore
|
||||
#else
|
||||
public RequestInformation ToGetRequestInformation(Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default)
|
||||
{
|
||||
#endif
|
||||
var requestInfo = new RequestInformation(Method.GET, UrlTemplate, PathParameters);
|
||||
requestInfo.Configure(requestConfiguration);
|
||||
requestInfo.Headers.TryAdd("Accept", "text/plain;q=0.9");
|
||||
return requestInfo;
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns a request builder with the provided arbitrary URL. Using this method means any other path or query parameters are ignored.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="global::Marechai.App.Computers.Count.CountRequestBuilder"/></returns>
|
||||
/// <param name="rawUrl">The raw URL to use for the request builder.</param>
|
||||
public global::Marechai.App.Computers.Count.CountRequestBuilder WithUrl(string rawUrl)
|
||||
{
|
||||
return new global::Marechai.App.Computers.Count.CountRequestBuilder(rawUrl, RequestAdapter);
|
||||
}
|
||||
/// <summary>
|
||||
/// Configuration for the request such as headers, query parameters, and middleware options.
|
||||
/// </summary>
|
||||
[Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
|
||||
public partial class CountRequestBuilderGetRequestConfiguration : RequestConfiguration<DefaultQueryParameters>
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma warning restore CS0618
|
||||
@@ -0,0 +1,91 @@
|
||||
// <auto-generated/>
|
||||
#pragma warning disable CS0618
|
||||
using Marechai.App.Models;
|
||||
using Microsoft.Kiota.Abstractions.Extensions;
|
||||
using Microsoft.Kiota.Abstractions.Serialization;
|
||||
using Microsoft.Kiota.Abstractions;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
using System;
|
||||
namespace Marechai.App.Computers.MaximumYear
|
||||
{
|
||||
/// <summary>
|
||||
/// Builds and executes requests for operations under \computers\maximum-year
|
||||
/// </summary>
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
|
||||
public partial class MaximumYearRequestBuilder : BaseRequestBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// Instantiates a new <see cref="global::Marechai.App.Computers.MaximumYear.MaximumYearRequestBuilder"/> and sets the default values.
|
||||
/// </summary>
|
||||
/// <param name="pathParameters">Path parameters for the request</param>
|
||||
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
|
||||
public MaximumYearRequestBuilder(Dictionary<string, object> pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/computers/maximum-year", pathParameters)
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// Instantiates a new <see cref="global::Marechai.App.Computers.MaximumYear.MaximumYearRequestBuilder"/> and sets the default values.
|
||||
/// </summary>
|
||||
/// <param name="rawUrl">The raw URL to use for the request builder.</param>
|
||||
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
|
||||
public MaximumYearRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/computers/maximum-year", rawUrl)
|
||||
{
|
||||
}
|
||||
/// <returns>A <see cref="UntypedNode"/></returns>
|
||||
/// <param name="cancellationToken">Cancellation token to use when cancelling requests</param>
|
||||
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
|
||||
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 400 status code</exception>
|
||||
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
|
||||
#nullable enable
|
||||
public async Task<UntypedNode?> GetAsync(Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default, CancellationToken cancellationToken = default)
|
||||
{
|
||||
#nullable restore
|
||||
#else
|
||||
public async Task<UntypedNode> GetAsync(Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default, CancellationToken cancellationToken = default)
|
||||
{
|
||||
#endif
|
||||
var requestInfo = ToGetRequestInformation(requestConfiguration);
|
||||
var errorMapping = new Dictionary<string, ParsableFactory<IParsable>>
|
||||
{
|
||||
{ "400", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
|
||||
};
|
||||
return await RequestAdapter.SendAsync<UntypedNode>(requestInfo, UntypedNode.CreateFromDiscriminatorValue, errorMapping, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
/// <returns>A <see cref="RequestInformation"/></returns>
|
||||
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
|
||||
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
|
||||
#nullable enable
|
||||
public RequestInformation ToGetRequestInformation(Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default)
|
||||
{
|
||||
#nullable restore
|
||||
#else
|
||||
public RequestInformation ToGetRequestInformation(Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default)
|
||||
{
|
||||
#endif
|
||||
var requestInfo = new RequestInformation(Method.GET, UrlTemplate, PathParameters);
|
||||
requestInfo.Configure(requestConfiguration);
|
||||
requestInfo.Headers.TryAdd("Accept", "text/plain;q=0.9");
|
||||
return requestInfo;
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns a request builder with the provided arbitrary URL. Using this method means any other path or query parameters are ignored.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="global::Marechai.App.Computers.MaximumYear.MaximumYearRequestBuilder"/></returns>
|
||||
/// <param name="rawUrl">The raw URL to use for the request builder.</param>
|
||||
public global::Marechai.App.Computers.MaximumYear.MaximumYearRequestBuilder WithUrl(string rawUrl)
|
||||
{
|
||||
return new global::Marechai.App.Computers.MaximumYear.MaximumYearRequestBuilder(rawUrl, RequestAdapter);
|
||||
}
|
||||
/// <summary>
|
||||
/// Configuration for the request such as headers, query parameters, and middleware options.
|
||||
/// </summary>
|
||||
[Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
|
||||
public partial class MaximumYearRequestBuilderGetRequestConfiguration : RequestConfiguration<DefaultQueryParameters>
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma warning restore CS0618
|
||||
@@ -0,0 +1,91 @@
|
||||
// <auto-generated/>
|
||||
#pragma warning disable CS0618
|
||||
using Marechai.App.Models;
|
||||
using Microsoft.Kiota.Abstractions.Extensions;
|
||||
using Microsoft.Kiota.Abstractions.Serialization;
|
||||
using Microsoft.Kiota.Abstractions;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
using System;
|
||||
namespace Marechai.App.Computers.MinimumYear
|
||||
{
|
||||
/// <summary>
|
||||
/// Builds and executes requests for operations under \computers\minimum-year
|
||||
/// </summary>
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
|
||||
public partial class MinimumYearRequestBuilder : BaseRequestBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// Instantiates a new <see cref="global::Marechai.App.Computers.MinimumYear.MinimumYearRequestBuilder"/> and sets the default values.
|
||||
/// </summary>
|
||||
/// <param name="pathParameters">Path parameters for the request</param>
|
||||
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
|
||||
public MinimumYearRequestBuilder(Dictionary<string, object> pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/computers/minimum-year", pathParameters)
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// Instantiates a new <see cref="global::Marechai.App.Computers.MinimumYear.MinimumYearRequestBuilder"/> and sets the default values.
|
||||
/// </summary>
|
||||
/// <param name="rawUrl">The raw URL to use for the request builder.</param>
|
||||
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
|
||||
public MinimumYearRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/computers/minimum-year", rawUrl)
|
||||
{
|
||||
}
|
||||
/// <returns>A <see cref="UntypedNode"/></returns>
|
||||
/// <param name="cancellationToken">Cancellation token to use when cancelling requests</param>
|
||||
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
|
||||
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 400 status code</exception>
|
||||
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
|
||||
#nullable enable
|
||||
public async Task<UntypedNode?> GetAsync(Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default, CancellationToken cancellationToken = default)
|
||||
{
|
||||
#nullable restore
|
||||
#else
|
||||
public async Task<UntypedNode> GetAsync(Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default, CancellationToken cancellationToken = default)
|
||||
{
|
||||
#endif
|
||||
var requestInfo = ToGetRequestInformation(requestConfiguration);
|
||||
var errorMapping = new Dictionary<string, ParsableFactory<IParsable>>
|
||||
{
|
||||
{ "400", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
|
||||
};
|
||||
return await RequestAdapter.SendAsync<UntypedNode>(requestInfo, UntypedNode.CreateFromDiscriminatorValue, errorMapping, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
/// <returns>A <see cref="RequestInformation"/></returns>
|
||||
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
|
||||
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
|
||||
#nullable enable
|
||||
public RequestInformation ToGetRequestInformation(Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default)
|
||||
{
|
||||
#nullable restore
|
||||
#else
|
||||
public RequestInformation ToGetRequestInformation(Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default)
|
||||
{
|
||||
#endif
|
||||
var requestInfo = new RequestInformation(Method.GET, UrlTemplate, PathParameters);
|
||||
requestInfo.Configure(requestConfiguration);
|
||||
requestInfo.Headers.TryAdd("Accept", "text/plain;q=0.9");
|
||||
return requestInfo;
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns a request builder with the provided arbitrary URL. Using this method means any other path or query parameters are ignored.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="global::Marechai.App.Computers.MinimumYear.MinimumYearRequestBuilder"/></returns>
|
||||
/// <param name="rawUrl">The raw URL to use for the request builder.</param>
|
||||
public global::Marechai.App.Computers.MinimumYear.MinimumYearRequestBuilder WithUrl(string rawUrl)
|
||||
{
|
||||
return new global::Marechai.App.Computers.MinimumYear.MinimumYearRequestBuilder(rawUrl, RequestAdapter);
|
||||
}
|
||||
/// <summary>
|
||||
/// Configuration for the request such as headers, query parameters, and middleware options.
|
||||
/// </summary>
|
||||
[Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
|
||||
public partial class MinimumYearRequestBuilderGetRequestConfiguration : RequestConfiguration<DefaultQueryParameters>
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma warning restore CS0618
|
||||
@@ -0,0 +1,48 @@
|
||||
// <auto-generated/>
|
||||
#pragma warning disable CS0618
|
||||
using Marechai.App.Consoles.ByLetter.Item;
|
||||
using Microsoft.Kiota.Abstractions.Extensions;
|
||||
using Microsoft.Kiota.Abstractions;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using System;
|
||||
namespace Marechai.App.Consoles.ByLetter
|
||||
{
|
||||
/// <summary>
|
||||
/// Builds and executes requests for operations under \consoles\by-letter
|
||||
/// </summary>
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
|
||||
public partial class ByLetterRequestBuilder : BaseRequestBuilder
|
||||
{
|
||||
/// <summary>Gets an item from the Marechai.App.consoles.byLetter.item collection</summary>
|
||||
/// <param name="position">Unique identifier of the item</param>
|
||||
/// <returns>A <see cref="global::Marechai.App.Consoles.ByLetter.Item.WithCItemRequestBuilder"/></returns>
|
||||
public global::Marechai.App.Consoles.ByLetter.Item.WithCItemRequestBuilder this[string position]
|
||||
{
|
||||
get
|
||||
{
|
||||
var urlTplParams = new Dictionary<string, object>(PathParameters);
|
||||
urlTplParams.Add("c", position);
|
||||
return new global::Marechai.App.Consoles.ByLetter.Item.WithCItemRequestBuilder(urlTplParams, RequestAdapter);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Instantiates a new <see cref="global::Marechai.App.Consoles.ByLetter.ByLetterRequestBuilder"/> and sets the default values.
|
||||
/// </summary>
|
||||
/// <param name="pathParameters">Path parameters for the request</param>
|
||||
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
|
||||
public ByLetterRequestBuilder(Dictionary<string, object> pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/consoles/by-letter", pathParameters)
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// Instantiates a new <see cref="global::Marechai.App.Consoles.ByLetter.ByLetterRequestBuilder"/> and sets the default values.
|
||||
/// </summary>
|
||||
/// <param name="rawUrl">The raw URL to use for the request builder.</param>
|
||||
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
|
||||
public ByLetterRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/consoles/by-letter", rawUrl)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma warning restore CS0618
|
||||
@@ -0,0 +1,92 @@
|
||||
// <auto-generated/>
|
||||
#pragma warning disable CS0618
|
||||
using Marechai.App.Models;
|
||||
using Microsoft.Kiota.Abstractions.Extensions;
|
||||
using Microsoft.Kiota.Abstractions.Serialization;
|
||||
using Microsoft.Kiota.Abstractions;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
using System;
|
||||
namespace Marechai.App.Consoles.ByLetter.Item
|
||||
{
|
||||
/// <summary>
|
||||
/// Builds and executes requests for operations under \consoles\by-letter\{c}
|
||||
/// </summary>
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
|
||||
public partial class WithCItemRequestBuilder : BaseRequestBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// Instantiates a new <see cref="global::Marechai.App.Consoles.ByLetter.Item.WithCItemRequestBuilder"/> and sets the default values.
|
||||
/// </summary>
|
||||
/// <param name="pathParameters">Path parameters for the request</param>
|
||||
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
|
||||
public WithCItemRequestBuilder(Dictionary<string, object> pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/consoles/by-letter/{c}", pathParameters)
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// Instantiates a new <see cref="global::Marechai.App.Consoles.ByLetter.Item.WithCItemRequestBuilder"/> and sets the default values.
|
||||
/// </summary>
|
||||
/// <param name="rawUrl">The raw URL to use for the request builder.</param>
|
||||
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
|
||||
public WithCItemRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/consoles/by-letter/{c}", rawUrl)
|
||||
{
|
||||
}
|
||||
/// <returns>A List<global::Marechai.App.Models.MachineDto></returns>
|
||||
/// <param name="cancellationToken">Cancellation token to use when cancelling requests</param>
|
||||
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
|
||||
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 400 status code</exception>
|
||||
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
|
||||
#nullable enable
|
||||
public async Task<List<global::Marechai.App.Models.MachineDto>?> GetAsync(Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default, CancellationToken cancellationToken = default)
|
||||
{
|
||||
#nullable restore
|
||||
#else
|
||||
public async Task<List<global::Marechai.App.Models.MachineDto>> GetAsync(Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default, CancellationToken cancellationToken = default)
|
||||
{
|
||||
#endif
|
||||
var requestInfo = ToGetRequestInformation(requestConfiguration);
|
||||
var errorMapping = new Dictionary<string, ParsableFactory<IParsable>>
|
||||
{
|
||||
{ "400", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
|
||||
};
|
||||
var collectionResult = await RequestAdapter.SendCollectionAsync<global::Marechai.App.Models.MachineDto>(requestInfo, global::Marechai.App.Models.MachineDto.CreateFromDiscriminatorValue, errorMapping, cancellationToken).ConfigureAwait(false);
|
||||
return collectionResult?.AsList();
|
||||
}
|
||||
/// <returns>A <see cref="RequestInformation"/></returns>
|
||||
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
|
||||
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
|
||||
#nullable enable
|
||||
public RequestInformation ToGetRequestInformation(Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default)
|
||||
{
|
||||
#nullable restore
|
||||
#else
|
||||
public RequestInformation ToGetRequestInformation(Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default)
|
||||
{
|
||||
#endif
|
||||
var requestInfo = new RequestInformation(Method.GET, UrlTemplate, PathParameters);
|
||||
requestInfo.Configure(requestConfiguration);
|
||||
requestInfo.Headers.TryAdd("Accept", "text/plain;q=0.9");
|
||||
return requestInfo;
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns a request builder with the provided arbitrary URL. Using this method means any other path or query parameters are ignored.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="global::Marechai.App.Consoles.ByLetter.Item.WithCItemRequestBuilder"/></returns>
|
||||
/// <param name="rawUrl">The raw URL to use for the request builder.</param>
|
||||
public global::Marechai.App.Consoles.ByLetter.Item.WithCItemRequestBuilder WithUrl(string rawUrl)
|
||||
{
|
||||
return new global::Marechai.App.Consoles.ByLetter.Item.WithCItemRequestBuilder(rawUrl, RequestAdapter);
|
||||
}
|
||||
/// <summary>
|
||||
/// Configuration for the request such as headers, query parameters, and middleware options.
|
||||
/// </summary>
|
||||
[Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
|
||||
public partial class WithCItemRequestBuilderGetRequestConfiguration : RequestConfiguration<DefaultQueryParameters>
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma warning restore CS0618
|
||||
@@ -0,0 +1,61 @@
|
||||
// <auto-generated/>
|
||||
#pragma warning disable CS0618
|
||||
using Marechai.App.Consoles.ByYear.Item;
|
||||
using Microsoft.Kiota.Abstractions.Extensions;
|
||||
using Microsoft.Kiota.Abstractions;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using System;
|
||||
namespace Marechai.App.Consoles.ByYear
|
||||
{
|
||||
/// <summary>
|
||||
/// Builds and executes requests for operations under \consoles\by-year
|
||||
/// </summary>
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
|
||||
public partial class ByYearRequestBuilder : BaseRequestBuilder
|
||||
{
|
||||
/// <summary>Gets an item from the Marechai.App.consoles.byYear.item collection</summary>
|
||||
/// <param name="position">Unique identifier of the item</param>
|
||||
/// <returns>A <see cref="global::Marechai.App.Consoles.ByYear.Item.WithYearItemRequestBuilder"/></returns>
|
||||
public global::Marechai.App.Consoles.ByYear.Item.WithYearItemRequestBuilder this[int position]
|
||||
{
|
||||
get
|
||||
{
|
||||
var urlTplParams = new Dictionary<string, object>(PathParameters);
|
||||
urlTplParams.Add("year", position);
|
||||
return new global::Marechai.App.Consoles.ByYear.Item.WithYearItemRequestBuilder(urlTplParams, RequestAdapter);
|
||||
}
|
||||
}
|
||||
/// <summary>Gets an item from the Marechai.App.consoles.byYear.item collection</summary>
|
||||
/// <param name="position">Unique identifier of the item</param>
|
||||
/// <returns>A <see cref="global::Marechai.App.Consoles.ByYear.Item.WithYearItemRequestBuilder"/></returns>
|
||||
[Obsolete("This indexer is deprecated and will be removed in the next major version. Use the one with the typed parameter instead.")]
|
||||
public global::Marechai.App.Consoles.ByYear.Item.WithYearItemRequestBuilder this[string position]
|
||||
{
|
||||
get
|
||||
{
|
||||
var urlTplParams = new Dictionary<string, object>(PathParameters);
|
||||
if (!string.IsNullOrWhiteSpace(position)) urlTplParams.Add("year", position);
|
||||
return new global::Marechai.App.Consoles.ByYear.Item.WithYearItemRequestBuilder(urlTplParams, RequestAdapter);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Instantiates a new <see cref="global::Marechai.App.Consoles.ByYear.ByYearRequestBuilder"/> and sets the default values.
|
||||
/// </summary>
|
||||
/// <param name="pathParameters">Path parameters for the request</param>
|
||||
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
|
||||
public ByYearRequestBuilder(Dictionary<string, object> pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/consoles/by-year", pathParameters)
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// Instantiates a new <see cref="global::Marechai.App.Consoles.ByYear.ByYearRequestBuilder"/> and sets the default values.
|
||||
/// </summary>
|
||||
/// <param name="rawUrl">The raw URL to use for the request builder.</param>
|
||||
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
|
||||
public ByYearRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/consoles/by-year", rawUrl)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma warning restore CS0618
|
||||
@@ -0,0 +1,92 @@
|
||||
// <auto-generated/>
|
||||
#pragma warning disable CS0618
|
||||
using Marechai.App.Models;
|
||||
using Microsoft.Kiota.Abstractions.Extensions;
|
||||
using Microsoft.Kiota.Abstractions.Serialization;
|
||||
using Microsoft.Kiota.Abstractions;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
using System;
|
||||
namespace Marechai.App.Consoles.ByYear.Item
|
||||
{
|
||||
/// <summary>
|
||||
/// Builds and executes requests for operations under \consoles\by-year\{year}
|
||||
/// </summary>
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
|
||||
public partial class WithYearItemRequestBuilder : BaseRequestBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// Instantiates a new <see cref="global::Marechai.App.Consoles.ByYear.Item.WithYearItemRequestBuilder"/> and sets the default values.
|
||||
/// </summary>
|
||||
/// <param name="pathParameters">Path parameters for the request</param>
|
||||
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
|
||||
public WithYearItemRequestBuilder(Dictionary<string, object> pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/consoles/by-year/{year}", pathParameters)
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// Instantiates a new <see cref="global::Marechai.App.Consoles.ByYear.Item.WithYearItemRequestBuilder"/> and sets the default values.
|
||||
/// </summary>
|
||||
/// <param name="rawUrl">The raw URL to use for the request builder.</param>
|
||||
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
|
||||
public WithYearItemRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/consoles/by-year/{year}", rawUrl)
|
||||
{
|
||||
}
|
||||
/// <returns>A List<global::Marechai.App.Models.MachineDto></returns>
|
||||
/// <param name="cancellationToken">Cancellation token to use when cancelling requests</param>
|
||||
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
|
||||
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 400 status code</exception>
|
||||
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
|
||||
#nullable enable
|
||||
public async Task<List<global::Marechai.App.Models.MachineDto>?> GetAsync(Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default, CancellationToken cancellationToken = default)
|
||||
{
|
||||
#nullable restore
|
||||
#else
|
||||
public async Task<List<global::Marechai.App.Models.MachineDto>> GetAsync(Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default, CancellationToken cancellationToken = default)
|
||||
{
|
||||
#endif
|
||||
var requestInfo = ToGetRequestInformation(requestConfiguration);
|
||||
var errorMapping = new Dictionary<string, ParsableFactory<IParsable>>
|
||||
{
|
||||
{ "400", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
|
||||
};
|
||||
var collectionResult = await RequestAdapter.SendCollectionAsync<global::Marechai.App.Models.MachineDto>(requestInfo, global::Marechai.App.Models.MachineDto.CreateFromDiscriminatorValue, errorMapping, cancellationToken).ConfigureAwait(false);
|
||||
return collectionResult?.AsList();
|
||||
}
|
||||
/// <returns>A <see cref="RequestInformation"/></returns>
|
||||
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
|
||||
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
|
||||
#nullable enable
|
||||
public RequestInformation ToGetRequestInformation(Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default)
|
||||
{
|
||||
#nullable restore
|
||||
#else
|
||||
public RequestInformation ToGetRequestInformation(Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default)
|
||||
{
|
||||
#endif
|
||||
var requestInfo = new RequestInformation(Method.GET, UrlTemplate, PathParameters);
|
||||
requestInfo.Configure(requestConfiguration);
|
||||
requestInfo.Headers.TryAdd("Accept", "text/plain;q=0.9");
|
||||
return requestInfo;
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns a request builder with the provided arbitrary URL. Using this method means any other path or query parameters are ignored.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="global::Marechai.App.Consoles.ByYear.Item.WithYearItemRequestBuilder"/></returns>
|
||||
/// <param name="rawUrl">The raw URL to use for the request builder.</param>
|
||||
public global::Marechai.App.Consoles.ByYear.Item.WithYearItemRequestBuilder WithUrl(string rawUrl)
|
||||
{
|
||||
return new global::Marechai.App.Consoles.ByYear.Item.WithYearItemRequestBuilder(rawUrl, RequestAdapter);
|
||||
}
|
||||
/// <summary>
|
||||
/// Configuration for the request such as headers, query parameters, and middleware options.
|
||||
/// </summary>
|
||||
[Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
|
||||
public partial class WithYearItemRequestBuilderGetRequestConfiguration : RequestConfiguration<DefaultQueryParameters>
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma warning restore CS0618
|
||||
@@ -1,5 +1,10 @@
|
||||
// <auto-generated/>
|
||||
#pragma warning disable CS0618
|
||||
using Marechai.App.Consoles.ByLetter;
|
||||
using Marechai.App.Consoles.ByYear;
|
||||
using Marechai.App.Consoles.Count;
|
||||
using Marechai.App.Consoles.MaximumYear;
|
||||
using Marechai.App.Consoles.MinimumYear;
|
||||
using Marechai.App.Models;
|
||||
using Microsoft.Kiota.Abstractions.Extensions;
|
||||
using Microsoft.Kiota.Abstractions.Serialization;
|
||||
@@ -17,6 +22,31 @@ namespace Marechai.App.Consoles
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
|
||||
public partial class ConsolesRequestBuilder : BaseRequestBuilder
|
||||
{
|
||||
/// <summary>The byLetter property</summary>
|
||||
public global::Marechai.App.Consoles.ByLetter.ByLetterRequestBuilder ByLetter
|
||||
{
|
||||
get => new global::Marechai.App.Consoles.ByLetter.ByLetterRequestBuilder(PathParameters, RequestAdapter);
|
||||
}
|
||||
/// <summary>The byYear property</summary>
|
||||
public global::Marechai.App.Consoles.ByYear.ByYearRequestBuilder ByYear
|
||||
{
|
||||
get => new global::Marechai.App.Consoles.ByYear.ByYearRequestBuilder(PathParameters, RequestAdapter);
|
||||
}
|
||||
/// <summary>The count property</summary>
|
||||
public global::Marechai.App.Consoles.Count.CountRequestBuilder Count
|
||||
{
|
||||
get => new global::Marechai.App.Consoles.Count.CountRequestBuilder(PathParameters, RequestAdapter);
|
||||
}
|
||||
/// <summary>The maximumYear property</summary>
|
||||
public global::Marechai.App.Consoles.MaximumYear.MaximumYearRequestBuilder MaximumYear
|
||||
{
|
||||
get => new global::Marechai.App.Consoles.MaximumYear.MaximumYearRequestBuilder(PathParameters, RequestAdapter);
|
||||
}
|
||||
/// <summary>The minimumYear property</summary>
|
||||
public global::Marechai.App.Consoles.MinimumYear.MinimumYearRequestBuilder MinimumYear
|
||||
{
|
||||
get => new global::Marechai.App.Consoles.MinimumYear.MinimumYearRequestBuilder(PathParameters, RequestAdapter);
|
||||
}
|
||||
/// <summary>
|
||||
/// Instantiates a new <see cref="global::Marechai.App.Consoles.ConsolesRequestBuilder"/> and sets the default values.
|
||||
/// </summary>
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
// <auto-generated/>
|
||||
#pragma warning disable CS0618
|
||||
using Marechai.App.Models;
|
||||
using Microsoft.Kiota.Abstractions.Extensions;
|
||||
using Microsoft.Kiota.Abstractions.Serialization;
|
||||
using Microsoft.Kiota.Abstractions;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
using System;
|
||||
namespace Marechai.App.Consoles.Count
|
||||
{
|
||||
/// <summary>
|
||||
/// Builds and executes requests for operations under \consoles\count
|
||||
/// </summary>
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
|
||||
public partial class CountRequestBuilder : BaseRequestBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// Instantiates a new <see cref="global::Marechai.App.Consoles.Count.CountRequestBuilder"/> and sets the default values.
|
||||
/// </summary>
|
||||
/// <param name="pathParameters">Path parameters for the request</param>
|
||||
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
|
||||
public CountRequestBuilder(Dictionary<string, object> pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/consoles/count", pathParameters)
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// Instantiates a new <see cref="global::Marechai.App.Consoles.Count.CountRequestBuilder"/> and sets the default values.
|
||||
/// </summary>
|
||||
/// <param name="rawUrl">The raw URL to use for the request builder.</param>
|
||||
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
|
||||
public CountRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/consoles/count", rawUrl)
|
||||
{
|
||||
}
|
||||
/// <returns>A <see cref="UntypedNode"/></returns>
|
||||
/// <param name="cancellationToken">Cancellation token to use when cancelling requests</param>
|
||||
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
|
||||
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 400 status code</exception>
|
||||
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
|
||||
#nullable enable
|
||||
public async Task<UntypedNode?> GetAsync(Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default, CancellationToken cancellationToken = default)
|
||||
{
|
||||
#nullable restore
|
||||
#else
|
||||
public async Task<UntypedNode> GetAsync(Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default, CancellationToken cancellationToken = default)
|
||||
{
|
||||
#endif
|
||||
var requestInfo = ToGetRequestInformation(requestConfiguration);
|
||||
var errorMapping = new Dictionary<string, ParsableFactory<IParsable>>
|
||||
{
|
||||
{ "400", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
|
||||
};
|
||||
return await RequestAdapter.SendAsync<UntypedNode>(requestInfo, UntypedNode.CreateFromDiscriminatorValue, errorMapping, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
/// <returns>A <see cref="RequestInformation"/></returns>
|
||||
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
|
||||
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
|
||||
#nullable enable
|
||||
public RequestInformation ToGetRequestInformation(Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default)
|
||||
{
|
||||
#nullable restore
|
||||
#else
|
||||
public RequestInformation ToGetRequestInformation(Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default)
|
||||
{
|
||||
#endif
|
||||
var requestInfo = new RequestInformation(Method.GET, UrlTemplate, PathParameters);
|
||||
requestInfo.Configure(requestConfiguration);
|
||||
requestInfo.Headers.TryAdd("Accept", "text/plain;q=0.9");
|
||||
return requestInfo;
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns a request builder with the provided arbitrary URL. Using this method means any other path or query parameters are ignored.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="global::Marechai.App.Consoles.Count.CountRequestBuilder"/></returns>
|
||||
/// <param name="rawUrl">The raw URL to use for the request builder.</param>
|
||||
public global::Marechai.App.Consoles.Count.CountRequestBuilder WithUrl(string rawUrl)
|
||||
{
|
||||
return new global::Marechai.App.Consoles.Count.CountRequestBuilder(rawUrl, RequestAdapter);
|
||||
}
|
||||
/// <summary>
|
||||
/// Configuration for the request such as headers, query parameters, and middleware options.
|
||||
/// </summary>
|
||||
[Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
|
||||
public partial class CountRequestBuilderGetRequestConfiguration : RequestConfiguration<DefaultQueryParameters>
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma warning restore CS0618
|
||||
@@ -0,0 +1,91 @@
|
||||
// <auto-generated/>
|
||||
#pragma warning disable CS0618
|
||||
using Marechai.App.Models;
|
||||
using Microsoft.Kiota.Abstractions.Extensions;
|
||||
using Microsoft.Kiota.Abstractions.Serialization;
|
||||
using Microsoft.Kiota.Abstractions;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
using System;
|
||||
namespace Marechai.App.Consoles.MaximumYear
|
||||
{
|
||||
/// <summary>
|
||||
/// Builds and executes requests for operations under \consoles\maximum-year
|
||||
/// </summary>
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
|
||||
public partial class MaximumYearRequestBuilder : BaseRequestBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// Instantiates a new <see cref="global::Marechai.App.Consoles.MaximumYear.MaximumYearRequestBuilder"/> and sets the default values.
|
||||
/// </summary>
|
||||
/// <param name="pathParameters">Path parameters for the request</param>
|
||||
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
|
||||
public MaximumYearRequestBuilder(Dictionary<string, object> pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/consoles/maximum-year", pathParameters)
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// Instantiates a new <see cref="global::Marechai.App.Consoles.MaximumYear.MaximumYearRequestBuilder"/> and sets the default values.
|
||||
/// </summary>
|
||||
/// <param name="rawUrl">The raw URL to use for the request builder.</param>
|
||||
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
|
||||
public MaximumYearRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/consoles/maximum-year", rawUrl)
|
||||
{
|
||||
}
|
||||
/// <returns>A <see cref="UntypedNode"/></returns>
|
||||
/// <param name="cancellationToken">Cancellation token to use when cancelling requests</param>
|
||||
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
|
||||
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 400 status code</exception>
|
||||
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
|
||||
#nullable enable
|
||||
public async Task<UntypedNode?> GetAsync(Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default, CancellationToken cancellationToken = default)
|
||||
{
|
||||
#nullable restore
|
||||
#else
|
||||
public async Task<UntypedNode> GetAsync(Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default, CancellationToken cancellationToken = default)
|
||||
{
|
||||
#endif
|
||||
var requestInfo = ToGetRequestInformation(requestConfiguration);
|
||||
var errorMapping = new Dictionary<string, ParsableFactory<IParsable>>
|
||||
{
|
||||
{ "400", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
|
||||
};
|
||||
return await RequestAdapter.SendAsync<UntypedNode>(requestInfo, UntypedNode.CreateFromDiscriminatorValue, errorMapping, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
/// <returns>A <see cref="RequestInformation"/></returns>
|
||||
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
|
||||
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
|
||||
#nullable enable
|
||||
public RequestInformation ToGetRequestInformation(Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default)
|
||||
{
|
||||
#nullable restore
|
||||
#else
|
||||
public RequestInformation ToGetRequestInformation(Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default)
|
||||
{
|
||||
#endif
|
||||
var requestInfo = new RequestInformation(Method.GET, UrlTemplate, PathParameters);
|
||||
requestInfo.Configure(requestConfiguration);
|
||||
requestInfo.Headers.TryAdd("Accept", "text/plain;q=0.9");
|
||||
return requestInfo;
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns a request builder with the provided arbitrary URL. Using this method means any other path or query parameters are ignored.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="global::Marechai.App.Consoles.MaximumYear.MaximumYearRequestBuilder"/></returns>
|
||||
/// <param name="rawUrl">The raw URL to use for the request builder.</param>
|
||||
public global::Marechai.App.Consoles.MaximumYear.MaximumYearRequestBuilder WithUrl(string rawUrl)
|
||||
{
|
||||
return new global::Marechai.App.Consoles.MaximumYear.MaximumYearRequestBuilder(rawUrl, RequestAdapter);
|
||||
}
|
||||
/// <summary>
|
||||
/// Configuration for the request such as headers, query parameters, and middleware options.
|
||||
/// </summary>
|
||||
[Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
|
||||
public partial class MaximumYearRequestBuilderGetRequestConfiguration : RequestConfiguration<DefaultQueryParameters>
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma warning restore CS0618
|
||||
@@ -0,0 +1,91 @@
|
||||
// <auto-generated/>
|
||||
#pragma warning disable CS0618
|
||||
using Marechai.App.Models;
|
||||
using Microsoft.Kiota.Abstractions.Extensions;
|
||||
using Microsoft.Kiota.Abstractions.Serialization;
|
||||
using Microsoft.Kiota.Abstractions;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
using System;
|
||||
namespace Marechai.App.Consoles.MinimumYear
|
||||
{
|
||||
/// <summary>
|
||||
/// Builds and executes requests for operations under \consoles\minimum-year
|
||||
/// </summary>
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
|
||||
public partial class MinimumYearRequestBuilder : BaseRequestBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// Instantiates a new <see cref="global::Marechai.App.Consoles.MinimumYear.MinimumYearRequestBuilder"/> and sets the default values.
|
||||
/// </summary>
|
||||
/// <param name="pathParameters">Path parameters for the request</param>
|
||||
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
|
||||
public MinimumYearRequestBuilder(Dictionary<string, object> pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/consoles/minimum-year", pathParameters)
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// Instantiates a new <see cref="global::Marechai.App.Consoles.MinimumYear.MinimumYearRequestBuilder"/> and sets the default values.
|
||||
/// </summary>
|
||||
/// <param name="rawUrl">The raw URL to use for the request builder.</param>
|
||||
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
|
||||
public MinimumYearRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/consoles/minimum-year", rawUrl)
|
||||
{
|
||||
}
|
||||
/// <returns>A <see cref="UntypedNode"/></returns>
|
||||
/// <param name="cancellationToken">Cancellation token to use when cancelling requests</param>
|
||||
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
|
||||
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 400 status code</exception>
|
||||
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
|
||||
#nullable enable
|
||||
public async Task<UntypedNode?> GetAsync(Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default, CancellationToken cancellationToken = default)
|
||||
{
|
||||
#nullable restore
|
||||
#else
|
||||
public async Task<UntypedNode> GetAsync(Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default, CancellationToken cancellationToken = default)
|
||||
{
|
||||
#endif
|
||||
var requestInfo = ToGetRequestInformation(requestConfiguration);
|
||||
var errorMapping = new Dictionary<string, ParsableFactory<IParsable>>
|
||||
{
|
||||
{ "400", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
|
||||
};
|
||||
return await RequestAdapter.SendAsync<UntypedNode>(requestInfo, UntypedNode.CreateFromDiscriminatorValue, errorMapping, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
/// <returns>A <see cref="RequestInformation"/></returns>
|
||||
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
|
||||
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
|
||||
#nullable enable
|
||||
public RequestInformation ToGetRequestInformation(Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default)
|
||||
{
|
||||
#nullable restore
|
||||
#else
|
||||
public RequestInformation ToGetRequestInformation(Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default)
|
||||
{
|
||||
#endif
|
||||
var requestInfo = new RequestInformation(Method.GET, UrlTemplate, PathParameters);
|
||||
requestInfo.Configure(requestConfiguration);
|
||||
requestInfo.Headers.TryAdd("Accept", "text/plain;q=0.9");
|
||||
return requestInfo;
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns a request builder with the provided arbitrary URL. Using this method means any other path or query parameters are ignored.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="global::Marechai.App.Consoles.MinimumYear.MinimumYearRequestBuilder"/></returns>
|
||||
/// <param name="rawUrl">The raw URL to use for the request builder.</param>
|
||||
public global::Marechai.App.Consoles.MinimumYear.MinimumYearRequestBuilder WithUrl(string rawUrl)
|
||||
{
|
||||
return new global::Marechai.App.Consoles.MinimumYear.MinimumYearRequestBuilder(rawUrl, RequestAdapter);
|
||||
}
|
||||
/// <summary>
|
||||
/// Configuration for the request such as headers, query parameters, and middleware options.
|
||||
/// </summary>
|
||||
[Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
|
||||
public partial class MinimumYearRequestBuilderGetRequestConfiguration : RequestConfiguration<DefaultQueryParameters>
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma warning restore CS0618
|
||||
@@ -55,6 +55,14 @@ namespace Marechai.App.Models
|
||||
#nullable restore
|
||||
#else
|
||||
public string FamilyName { get; set; }
|
||||
#endif
|
||||
/// <summary>The gpus property</summary>
|
||||
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
|
||||
#nullable enable
|
||||
public List<global::Marechai.App.Models.GpuDto>? Gpus { get; set; }
|
||||
#nullable restore
|
||||
#else
|
||||
public List<global::Marechai.App.Models.GpuDto> Gpus { get; set; }
|
||||
#endif
|
||||
/// <summary>The id property</summary>
|
||||
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
|
||||
@@ -66,6 +74,14 @@ namespace Marechai.App.Models
|
||||
#endif
|
||||
/// <summary>The introduced property</summary>
|
||||
public DateTimeOffset? Introduced { get; set; }
|
||||
/// <summary>The memory property</summary>
|
||||
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
|
||||
#nullable enable
|
||||
public List<global::Marechai.App.Models.MemoryDto>? Memory { get; set; }
|
||||
#nullable restore
|
||||
#else
|
||||
public List<global::Marechai.App.Models.MemoryDto> Memory { get; set; }
|
||||
#endif
|
||||
/// <summary>The model property</summary>
|
||||
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
|
||||
#nullable enable
|
||||
@@ -81,6 +97,30 @@ namespace Marechai.App.Models
|
||||
#nullable restore
|
||||
#else
|
||||
public string Name { get; set; }
|
||||
#endif
|
||||
/// <summary>The processors property</summary>
|
||||
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
|
||||
#nullable enable
|
||||
public List<global::Marechai.App.Models.ProcessorDto>? Processors { get; set; }
|
||||
#nullable restore
|
||||
#else
|
||||
public List<global::Marechai.App.Models.ProcessorDto> Processors { get; set; }
|
||||
#endif
|
||||
/// <summary>The soundSynthesizers property</summary>
|
||||
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
|
||||
#nullable enable
|
||||
public List<global::Marechai.App.Models.SoundSynthDto>? SoundSynthesizers { get; set; }
|
||||
#nullable restore
|
||||
#else
|
||||
public List<global::Marechai.App.Models.SoundSynthDto> SoundSynthesizers { get; set; }
|
||||
#endif
|
||||
/// <summary>The storage property</summary>
|
||||
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
|
||||
#nullable enable
|
||||
public List<global::Marechai.App.Models.StorageDto>? Storage { get; set; }
|
||||
#nullable restore
|
||||
#else
|
||||
public List<global::Marechai.App.Models.StorageDto> Storage { get; set; }
|
||||
#endif
|
||||
/// <summary>The type property</summary>
|
||||
public int? Type { get; set; }
|
||||
@@ -115,10 +155,15 @@ namespace Marechai.App.Models
|
||||
{ "family", n => { Family = n.GetStringValue(); } },
|
||||
{ "family_id", n => { FamilyId = n.GetObjectValue<UntypedNode>(UntypedNode.CreateFromDiscriminatorValue); } },
|
||||
{ "family_name", n => { FamilyName = n.GetStringValue(); } },
|
||||
{ "gpus", n => { Gpus = n.GetCollectionOfObjectValues<global::Marechai.App.Models.GpuDto>(global::Marechai.App.Models.GpuDto.CreateFromDiscriminatorValue)?.AsList(); } },
|
||||
{ "id", n => { Id = n.GetObjectValue<UntypedNode>(UntypedNode.CreateFromDiscriminatorValue); } },
|
||||
{ "introduced", n => { Introduced = n.GetDateTimeOffsetValue(); } },
|
||||
{ "memory", n => { Memory = n.GetCollectionOfObjectValues<global::Marechai.App.Models.MemoryDto>(global::Marechai.App.Models.MemoryDto.CreateFromDiscriminatorValue)?.AsList(); } },
|
||||
{ "model", n => { Model = n.GetStringValue(); } },
|
||||
{ "name", n => { Name = n.GetStringValue(); } },
|
||||
{ "processors", n => { Processors = n.GetCollectionOfObjectValues<global::Marechai.App.Models.ProcessorDto>(global::Marechai.App.Models.ProcessorDto.CreateFromDiscriminatorValue)?.AsList(); } },
|
||||
{ "soundSynthesizers", n => { SoundSynthesizers = n.GetCollectionOfObjectValues<global::Marechai.App.Models.SoundSynthDto>(global::Marechai.App.Models.SoundSynthDto.CreateFromDiscriminatorValue)?.AsList(); } },
|
||||
{ "storage", n => { Storage = n.GetCollectionOfObjectValues<global::Marechai.App.Models.StorageDto>(global::Marechai.App.Models.StorageDto.CreateFromDiscriminatorValue)?.AsList(); } },
|
||||
{ "type", n => { Type = n.GetIntValue(); } },
|
||||
};
|
||||
}
|
||||
@@ -135,10 +180,15 @@ namespace Marechai.App.Models
|
||||
writer.WriteStringValue("family", Family);
|
||||
writer.WriteObjectValue<UntypedNode>("family_id", FamilyId);
|
||||
writer.WriteStringValue("family_name", FamilyName);
|
||||
writer.WriteCollectionOfObjectValues<global::Marechai.App.Models.GpuDto>("gpus", Gpus);
|
||||
writer.WriteObjectValue<UntypedNode>("id", Id);
|
||||
writer.WriteDateTimeOffsetValue("introduced", Introduced);
|
||||
writer.WriteCollectionOfObjectValues<global::Marechai.App.Models.MemoryDto>("memory", Memory);
|
||||
writer.WriteStringValue("model", Model);
|
||||
writer.WriteStringValue("name", Name);
|
||||
writer.WriteCollectionOfObjectValues<global::Marechai.App.Models.ProcessorDto>("processors", Processors);
|
||||
writer.WriteCollectionOfObjectValues<global::Marechai.App.Models.SoundSynthDto>("soundSynthesizers", SoundSynthesizers);
|
||||
writer.WriteCollectionOfObjectValues<global::Marechai.App.Models.StorageDto>("storage", Storage);
|
||||
writer.WriteIntValue("type", Type);
|
||||
writer.WriteAdditionalData(AdditionalData);
|
||||
}
|
||||
|
||||
83
Marechai.App/Services/Client/Models/MemoryDto.cs
Normal file
83
Marechai.App/Services/Client/Models/MemoryDto.cs
Normal file
@@ -0,0 +1,83 @@
|
||||
// <auto-generated/>
|
||||
#pragma warning disable CS0618
|
||||
using Microsoft.Kiota.Abstractions.Extensions;
|
||||
using Microsoft.Kiota.Abstractions.Serialization;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System;
|
||||
namespace Marechai.App.Models
|
||||
{
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
|
||||
#pragma warning disable CS1591
|
||||
public partial class MemoryDto : IAdditionalDataHolder, IParsable
|
||||
#pragma warning restore CS1591
|
||||
{
|
||||
/// <summary>Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well.</summary>
|
||||
public IDictionary<string, object> AdditionalData { get; set; }
|
||||
/// <summary>The size property</summary>
|
||||
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
|
||||
#nullable enable
|
||||
public UntypedNode? Size { get; set; }
|
||||
#nullable restore
|
||||
#else
|
||||
public UntypedNode Size { get; set; }
|
||||
#endif
|
||||
/// <summary>The speed property</summary>
|
||||
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
|
||||
#nullable enable
|
||||
public UntypedNode? Speed { get; set; }
|
||||
#nullable restore
|
||||
#else
|
||||
public UntypedNode Speed { get; set; }
|
||||
#endif
|
||||
/// <summary>The type property</summary>
|
||||
public int? Type { get; set; }
|
||||
/// <summary>The usage property</summary>
|
||||
public int? Usage { get; set; }
|
||||
/// <summary>
|
||||
/// Instantiates a new <see cref="global::Marechai.App.Models.MemoryDto"/> and sets the default values.
|
||||
/// </summary>
|
||||
public MemoryDto()
|
||||
{
|
||||
AdditionalData = new Dictionary<string, object>();
|
||||
}
|
||||
/// <summary>
|
||||
/// Creates a new instance of the appropriate class based on discriminator value
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="global::Marechai.App.Models.MemoryDto"/></returns>
|
||||
/// <param name="parseNode">The parse node to use to read the discriminator value and create the object</param>
|
||||
public static global::Marechai.App.Models.MemoryDto CreateFromDiscriminatorValue(IParseNode parseNode)
|
||||
{
|
||||
if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode));
|
||||
return new global::Marechai.App.Models.MemoryDto();
|
||||
}
|
||||
/// <summary>
|
||||
/// The deserialization information for the current model
|
||||
/// </summary>
|
||||
/// <returns>A IDictionary<string, Action<IParseNode>></returns>
|
||||
public virtual IDictionary<string, Action<IParseNode>> GetFieldDeserializers()
|
||||
{
|
||||
return new Dictionary<string, Action<IParseNode>>
|
||||
{
|
||||
{ "size", n => { Size = n.GetObjectValue<UntypedNode>(UntypedNode.CreateFromDiscriminatorValue); } },
|
||||
{ "speed", n => { Speed = n.GetObjectValue<UntypedNode>(UntypedNode.CreateFromDiscriminatorValue); } },
|
||||
{ "type", n => { Type = n.GetIntValue(); } },
|
||||
{ "usage", n => { Usage = n.GetIntValue(); } },
|
||||
};
|
||||
}
|
||||
/// <summary>
|
||||
/// Serializes information the current object
|
||||
/// </summary>
|
||||
/// <param name="writer">Serialization writer to use to serialize this model</param>
|
||||
public virtual void Serialize(ISerializationWriter writer)
|
||||
{
|
||||
if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer));
|
||||
writer.WriteObjectValue<UntypedNode>("size", Size);
|
||||
writer.WriteObjectValue<UntypedNode>("speed", Speed);
|
||||
writer.WriteIntValue("type", Type);
|
||||
writer.WriteIntValue("usage", Usage);
|
||||
writer.WriteAdditionalData(AdditionalData);
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma warning restore CS0618
|
||||
73
Marechai.App/Services/Client/Models/StorageDto.cs
Normal file
73
Marechai.App/Services/Client/Models/StorageDto.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
// <auto-generated/>
|
||||
#pragma warning disable CS0618
|
||||
using Microsoft.Kiota.Abstractions.Extensions;
|
||||
using Microsoft.Kiota.Abstractions.Serialization;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System;
|
||||
namespace Marechai.App.Models
|
||||
{
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
|
||||
#pragma warning disable CS1591
|
||||
public partial class StorageDto : IAdditionalDataHolder, IParsable
|
||||
#pragma warning restore CS1591
|
||||
{
|
||||
/// <summary>Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well.</summary>
|
||||
public IDictionary<string, object> AdditionalData { get; set; }
|
||||
/// <summary>The capacity property</summary>
|
||||
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
|
||||
#nullable enable
|
||||
public UntypedNode? Capacity { get; set; }
|
||||
#nullable restore
|
||||
#else
|
||||
public UntypedNode Capacity { get; set; }
|
||||
#endif
|
||||
/// <summary>The interface property</summary>
|
||||
public int? Interface { get; set; }
|
||||
/// <summary>The type property</summary>
|
||||
public int? Type { get; set; }
|
||||
/// <summary>
|
||||
/// Instantiates a new <see cref="global::Marechai.App.Models.StorageDto"/> and sets the default values.
|
||||
/// </summary>
|
||||
public StorageDto()
|
||||
{
|
||||
AdditionalData = new Dictionary<string, object>();
|
||||
}
|
||||
/// <summary>
|
||||
/// Creates a new instance of the appropriate class based on discriminator value
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="global::Marechai.App.Models.StorageDto"/></returns>
|
||||
/// <param name="parseNode">The parse node to use to read the discriminator value and create the object</param>
|
||||
public static global::Marechai.App.Models.StorageDto CreateFromDiscriminatorValue(IParseNode parseNode)
|
||||
{
|
||||
if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode));
|
||||
return new global::Marechai.App.Models.StorageDto();
|
||||
}
|
||||
/// <summary>
|
||||
/// The deserialization information for the current model
|
||||
/// </summary>
|
||||
/// <returns>A IDictionary<string, Action<IParseNode>></returns>
|
||||
public virtual IDictionary<string, Action<IParseNode>> GetFieldDeserializers()
|
||||
{
|
||||
return new Dictionary<string, Action<IParseNode>>
|
||||
{
|
||||
{ "capacity", n => { Capacity = n.GetObjectValue<UntypedNode>(UntypedNode.CreateFromDiscriminatorValue); } },
|
||||
{ "interface", n => { Interface = n.GetIntValue(); } },
|
||||
{ "type", n => { Type = n.GetIntValue(); } },
|
||||
};
|
||||
}
|
||||
/// <summary>
|
||||
/// Serializes information the current object
|
||||
/// </summary>
|
||||
/// <param name="writer">Serialization writer to use to serialize this model</param>
|
||||
public virtual void Serialize(ISerializationWriter writer)
|
||||
{
|
||||
if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer));
|
||||
writer.WriteObjectValue<UntypedNode>("capacity", Capacity);
|
||||
writer.WriteIntValue("interface", Interface);
|
||||
writer.WriteIntValue("type", Type);
|
||||
writer.WriteAdditionalData(AdditionalData);
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma warning restore CS0618
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"descriptionHash": "4C4317F1318B3D4CA2225D2F84196E63FE3991CAA0B4FAC3BDA2432C98D3457223C321CFD97E2BC392D20DCE9E265F204F4B0E90C7FE300BC876152A4FC07520",
|
||||
"descriptionHash": "D113F1327CF7DE3F19E825040CA90DB79CEEC1636CED7E314A2D47CB82985CF9BC542185433D69366B0B36C3836966BDE3778B69AA15A0D11A063BE5571BCA5D",
|
||||
"descriptionLocation": "http://localhost:5023/openapi/v1.json",
|
||||
"lockFileVersion": "1.0.0",
|
||||
"kiotaVersion": "1.29.0",
|
||||
|
||||
77
Marechai.App/Services/CompaniesService.cs
Normal file
77
Marechai.App/Services/CompaniesService.cs
Normal file
@@ -0,0 +1,77 @@
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Marechai.App.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Service for fetching companies data from the API
|
||||
/// </summary>
|
||||
public class CompaniesService
|
||||
{
|
||||
private readonly ApiClient _apiClient;
|
||||
private readonly ILogger<CompaniesService> _logger;
|
||||
|
||||
public CompaniesService(ApiClient apiClient, ILogger<CompaniesService> logger)
|
||||
{
|
||||
_apiClient = apiClient;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all companies
|
||||
/// </summary>
|
||||
public async Task<List<CompanyDto>> GetAllCompaniesAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("Fetching all companies from API");
|
||||
|
||||
List<CompanyDto>? companies = await _apiClient.Companies.GetAsync();
|
||||
|
||||
if(companies == null) return [];
|
||||
|
||||
_logger.LogInformation("Successfully fetched {Count} total companies", companies.Count);
|
||||
|
||||
return companies;
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error fetching all companies from API");
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a single company by ID
|
||||
/// </summary>
|
||||
public async Task<CompanyDto?> GetCompanyByIdAsync(int companyId)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("Fetching company {CompanyId} from API", companyId);
|
||||
|
||||
CompanyDto? company = await _apiClient.Companies[companyId].GetAsync();
|
||||
|
||||
if(company == null)
|
||||
{
|
||||
_logger.LogWarning("Company {CompanyId} not found", companyId);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
_logger.LogInformation("Successfully fetched company {CompanyId}: {CompanyName}", companyId, company.Name);
|
||||
|
||||
return company;
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error fetching company {CompanyId} from API", companyId);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
101
Marechai.App/Services/CompanyDetailService.cs
Normal file
101
Marechai.App/Services/CompanyDetailService.cs
Normal file
@@ -0,0 +1,101 @@
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Marechai.App.Models;
|
||||
|
||||
namespace Marechai.App.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Service for fetching company details from the API
|
||||
/// </summary>
|
||||
public class CompanyDetailService
|
||||
{
|
||||
private readonly ApiClient _apiClient;
|
||||
private readonly ILogger<CompanyDetailService> _logger;
|
||||
|
||||
public CompanyDetailService(ApiClient apiClient, ILogger<CompanyDetailService> logger)
|
||||
{
|
||||
_apiClient = apiClient;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a single company by ID with full details
|
||||
/// </summary>
|
||||
public async Task<CompanyDto?> GetCompanyByIdAsync(int companyId)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("Fetching company {CompanyId} from API", companyId);
|
||||
|
||||
CompanyDto? company = await _apiClient.Companies[companyId].GetAsync();
|
||||
|
||||
if(company == null)
|
||||
{
|
||||
_logger.LogWarning("Company {CompanyId} not found", companyId);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
_logger.LogInformation("Successfully fetched company {CompanyId}: {CompanyName}", companyId, company.Name);
|
||||
|
||||
return company;
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error fetching company {CompanyId} from API", companyId);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets machines (computers) made by a company
|
||||
/// </summary>
|
||||
public async Task<List<MachineDto>> GetComputersByCompanyAsync(int companyId)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("Fetching computers for company {CompanyId}", companyId);
|
||||
|
||||
List<MachineDto>? machines = await _apiClient.Companies[companyId].Machines.GetAsync();
|
||||
|
||||
if(machines == null) return [];
|
||||
|
||||
_logger.LogInformation("Successfully fetched {Count} computers for company {CompanyId}", machines.Count, companyId);
|
||||
|
||||
return machines;
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error fetching computers for company {CompanyId}", companyId);
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sold-to company (when company was sold, merged, or renamed)
|
||||
/// </summary>
|
||||
public async Task<CompanyDto?> GetSoldToCompanyAsync(int? companyId)
|
||||
{
|
||||
if(companyId is null or <= 0) return null;
|
||||
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("Fetching sold-to company {CompanyId}", companyId);
|
||||
|
||||
CompanyDto? company = await _apiClient.Companies[companyId.Value].GetAsync();
|
||||
|
||||
return company;
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error fetching sold-to company {CompanyId}", companyId);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ namespace Marechai.App.Services;
|
||||
public class CompositeSerializationWriterFactory : ISerializationWriterFactory
|
||||
{
|
||||
// Internal list of registered factories.
|
||||
private readonly List<ISerializationWriterFactory> _factories = new();
|
||||
private readonly List<ISerializationWriterFactory> _factories = [];
|
||||
|
||||
// This method loops through each registered factory and returns the first one that supports the content type.
|
||||
public ISerializationWriter GetSerializationWriter(string contentType)
|
||||
|
||||
29
Marechai.App/Services/ComputersListFilterContext.cs
Normal file
29
Marechai.App/Services/ComputersListFilterContext.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
namespace Marechai.App.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Service to hold the current filter context for the computers list view
|
||||
/// </summary>
|
||||
public interface IComputersListFilterContext
|
||||
{
|
||||
ComputerListFilterType FilterType { get; set; }
|
||||
string FilterValue { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implementation of the computers list filter context
|
||||
/// </summary>
|
||||
public class ComputersListFilterContext : IComputersListFilterContext
|
||||
{
|
||||
public ComputerListFilterType FilterType { get; set; } = ComputerListFilterType.All;
|
||||
public string FilterValue { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enum for computer filter types
|
||||
/// </summary>
|
||||
public enum ComputerListFilterType
|
||||
{
|
||||
All,
|
||||
Letter,
|
||||
Year
|
||||
}
|
||||
208
Marechai.App/Services/ComputersService.cs
Normal file
208
Marechai.App/Services/ComputersService.cs
Normal file
@@ -0,0 +1,208 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Marechai.App.Helpers;
|
||||
using Microsoft.Kiota.Abstractions.Serialization;
|
||||
|
||||
namespace Marechai.App.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Service for fetching and managing computers from the Marechai API
|
||||
/// </summary>
|
||||
public class ComputersService
|
||||
{
|
||||
private readonly ApiClient _apiClient;
|
||||
private readonly ILogger<ComputersService> _logger;
|
||||
|
||||
public ComputersService(ApiClient apiClient, ILogger<ComputersService> logger)
|
||||
{
|
||||
_apiClient = apiClient;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fetches the total count of computers from the API
|
||||
/// </summary>
|
||||
/// <returns>Total number of computers, or 0 if API call fails</returns>
|
||||
public async Task<int> GetComputersCountAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("Fetching computers count from API");
|
||||
UntypedNode result = await _apiClient.Computers.Count.GetAsync();
|
||||
|
||||
// Extract integer value from UntypedNode
|
||||
// UntypedNode wraps a JsonElement, we need to parse it
|
||||
int count = UntypedNodeExtractor.ExtractInt(result);
|
||||
_logger.LogInformation("Successfully fetched computers count: {Count}", count);
|
||||
|
||||
return count;
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error fetching computers count from API");
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fetches the minimum year of computers from the API
|
||||
/// </summary>
|
||||
/// <returns>Minimum year, or 0 if API call fails</returns>
|
||||
public async Task<int> GetMinimumYearAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("Fetching minimum year from API");
|
||||
UntypedNode result = await _apiClient.Computers.MinimumYear.GetAsync();
|
||||
|
||||
// Extract integer value from UntypedNode
|
||||
int year = UntypedNodeExtractor.ExtractInt(result);
|
||||
_logger.LogInformation("Successfully fetched minimum year: {Year}", year);
|
||||
|
||||
return year;
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error fetching minimum year from API");
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fetches the maximum year of computers from the API
|
||||
/// </summary>
|
||||
/// <returns>Maximum year, or 0 if API call fails</returns>
|
||||
public async Task<int> GetMaximumYearAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("Fetching maximum year from API");
|
||||
UntypedNode result = await _apiClient.Computers.MaximumYear.GetAsync();
|
||||
|
||||
// Extract integer value from UntypedNode
|
||||
int year = UntypedNodeExtractor.ExtractInt(result);
|
||||
_logger.LogInformation("Successfully fetched maximum year: {Year}", year);
|
||||
|
||||
return year;
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error fetching maximum year from API");
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to extract an integer from an UntypedNode
|
||||
/// </summary>
|
||||
/// <summary>
|
||||
/// Fetches computers filtered by starting letter from the API
|
||||
/// </summary>
|
||||
public async Task<List<MachineDto>> GetComputersByLetterAsync(char letter)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("Fetching computers starting with '{Letter}' from API", letter);
|
||||
|
||||
List<MachineDto> computers = await _apiClient.Computers.ByLetter[letter.ToString()].GetAsync();
|
||||
|
||||
if(computers == null) return [];
|
||||
|
||||
_logger.LogInformation("Successfully fetched {Count} computers starting with '{Letter}'",
|
||||
computers.Count,
|
||||
letter);
|
||||
|
||||
return computers;
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error fetching computers by letter '{Letter}' from API", letter);
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fetches computers filtered by year from the API
|
||||
/// </summary>
|
||||
public async Task<List<MachineDto>> GetComputersByYearAsync(int year)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("Fetching computers from year {Year} from API", year);
|
||||
|
||||
List<MachineDto> computers = await _apiClient.Computers.ByYear[year].GetAsync();
|
||||
|
||||
if(computers == null) return [];
|
||||
|
||||
_logger.LogInformation("Successfully fetched {Count} computers from year {Year}", computers.Count, year);
|
||||
|
||||
return computers;
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error fetching computers by year {Year} from API", year);
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fetches all computers from the API
|
||||
/// </summary>
|
||||
public async Task<List<MachineDto>> GetAllComputersAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("Fetching all computers from API");
|
||||
|
||||
List<MachineDto> computers = await _apiClient.Computers.GetAsync();
|
||||
|
||||
if(computers == null) return [];
|
||||
|
||||
_logger.LogInformation("Successfully fetched {Count} total computers", computers.Count);
|
||||
|
||||
return computers;
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error fetching all computers from API");
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fetches a single machine with full details by ID from the API
|
||||
/// </summary>
|
||||
public async Task<MachineDto?> GetMachineByIdAsync(int machineId)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("Fetching machine {MachineId} from API", machineId);
|
||||
|
||||
MachineDto? machine = await _apiClient.Machines[machineId].Full.GetAsync();
|
||||
|
||||
if(machine == null)
|
||||
{
|
||||
_logger.LogWarning("Machine {MachineId} not found", machineId);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
_logger.LogInformation("Successfully fetched machine {MachineId}: {MachineName}", machineId, machine.Name);
|
||||
|
||||
return machine;
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error fetching machine {MachineId} from API", machineId);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
29
Marechai.App/Services/ConsolesListFilterContext.cs
Normal file
29
Marechai.App/Services/ConsolesListFilterContext.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
namespace Marechai.App.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Context for filtering consoles by various criteria
|
||||
/// </summary>
|
||||
public interface IConsolesListFilterContext
|
||||
{
|
||||
ConsoleListFilterType FilterType { get; set; }
|
||||
string FilterValue { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implementation of the consoles list filter context
|
||||
/// </summary>
|
||||
public class ConsolesListFilterContext : IConsolesListFilterContext
|
||||
{
|
||||
public ConsoleListFilterType FilterType { get; set; } = ConsoleListFilterType.All;
|
||||
public string FilterValue { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enumeration for console list filter types
|
||||
/// </summary>
|
||||
public enum ConsoleListFilterType
|
||||
{
|
||||
All,
|
||||
Letter,
|
||||
Year
|
||||
}
|
||||
205
Marechai.App/Services/ConsolesService.cs
Normal file
205
Marechai.App/Services/ConsolesService.cs
Normal file
@@ -0,0 +1,205 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Marechai.App.Helpers;
|
||||
using Microsoft.Kiota.Abstractions.Serialization;
|
||||
|
||||
namespace Marechai.App.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Service for fetching and managing consoles from the Marechai API
|
||||
/// </summary>
|
||||
public class ConsolesService
|
||||
{
|
||||
private readonly ApiClient _apiClient;
|
||||
private readonly ILogger<ConsolesService> _logger;
|
||||
|
||||
public ConsolesService(ApiClient apiClient, ILogger<ConsolesService> logger)
|
||||
{
|
||||
_apiClient = apiClient;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fetches the total count of consoles from the API
|
||||
/// </summary>
|
||||
/// <returns>Total number of consoles, or 0 if API call fails</returns>
|
||||
public async Task<int> GetConsolesCountAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("Fetching consoles count from API");
|
||||
UntypedNode result = await _apiClient.Consoles.Count.GetAsync();
|
||||
|
||||
// Extract integer value from UntypedNode
|
||||
// UntypedNode wraps a JsonElement, we need to parse it
|
||||
int count = UntypedNodeExtractor.ExtractInt(result);
|
||||
_logger.LogInformation("Successfully fetched consoles count: {Count}", count);
|
||||
|
||||
return count;
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error fetching consoles count from API");
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fetches the minimum year of consoles from the API
|
||||
/// </summary>
|
||||
/// <returns>Minimum year, or 0 if API call fails</returns>
|
||||
public async Task<int> GetMinimumYearAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("Fetching minimum year from API");
|
||||
UntypedNode result = await _apiClient.Consoles.MinimumYear.GetAsync();
|
||||
|
||||
// Extract integer value from UntypedNode
|
||||
int year = UntypedNodeExtractor.ExtractInt(result);
|
||||
_logger.LogInformation("Successfully fetched minimum year: {Year}", year);
|
||||
|
||||
return year;
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error fetching minimum year from API");
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fetches the maximum year of consoles from the API
|
||||
/// </summary>
|
||||
/// <returns>Maximum year, or 0 if API call fails</returns>
|
||||
public async Task<int> GetMaximumYearAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("Fetching maximum year from API");
|
||||
UntypedNode result = await _apiClient.Consoles.MaximumYear.GetAsync();
|
||||
|
||||
// Extract integer value from UntypedNode
|
||||
int year = UntypedNodeExtractor.ExtractInt(result);
|
||||
_logger.LogInformation("Successfully fetched maximum year: {Year}", year);
|
||||
|
||||
return year;
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error fetching maximum year from API");
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fetches consoles filtered by starting letter from the API
|
||||
/// </summary>
|
||||
public async Task<List<MachineDto>> GetConsolesByLetterAsync(char letter)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("Fetching consoles starting with '{Letter}' from API", letter);
|
||||
|
||||
List<MachineDto> consoles = await _apiClient.Consoles.ByLetter[letter.ToString()].GetAsync();
|
||||
|
||||
if(consoles == null) return [];
|
||||
|
||||
_logger.LogInformation("Successfully fetched {Count} consoles starting with '{Letter}'",
|
||||
consoles.Count,
|
||||
letter);
|
||||
|
||||
return consoles;
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error fetching consoles by letter '{Letter}' from API", letter);
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fetches consoles filtered by year from the API
|
||||
/// </summary>
|
||||
public async Task<List<MachineDto>> GetConsolesByYearAsync(int year)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("Fetching consoles from year {Year} from API", year);
|
||||
|
||||
List<MachineDto> consoles = await _apiClient.Consoles.ByYear[year].GetAsync();
|
||||
|
||||
if(consoles == null) return [];
|
||||
|
||||
_logger.LogInformation("Successfully fetched {Count} consoles from year {Year}", consoles.Count, year);
|
||||
|
||||
return consoles;
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error fetching consoles by year {Year} from API", year);
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fetches all consoles from the API
|
||||
/// </summary>
|
||||
public async Task<List<MachineDto>> GetAllConsolesAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("Fetching all consoles from API");
|
||||
|
||||
List<MachineDto> consoles = await _apiClient.Consoles.GetAsync();
|
||||
|
||||
if(consoles == null) return [];
|
||||
|
||||
_logger.LogInformation("Successfully fetched {Count} total consoles", consoles.Count);
|
||||
|
||||
return consoles;
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error fetching all consoles from API");
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fetches a single machine with full details by ID from the API
|
||||
/// </summary>
|
||||
public async Task<MachineDto?> GetMachineByIdAsync(int machineId)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("Fetching machine {MachineId} from API", machineId);
|
||||
|
||||
MachineDto? machine = await _apiClient.Machines[machineId].Full.GetAsync();
|
||||
|
||||
if(machine == null)
|
||||
{
|
||||
_logger.LogWarning("Machine {MachineId} not found", machineId);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
_logger.LogInformation("Successfully fetched machine {MachineId}: {MachineName}", machineId, machine.Name);
|
||||
|
||||
return machine;
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error fetching machine {MachineId} from API", machineId);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,13 +30,13 @@ public class NewsService
|
||||
List<NewsDto> news = await _apiClient.News.Latest.GetAsync();
|
||||
_logger.LogInformation("Successfully fetched {Count} news items", news?.Count ?? 0);
|
||||
|
||||
return news ?? new List<NewsDto>();
|
||||
return news ?? [];
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error fetching latest news from API");
|
||||
|
||||
return new List<NewsDto>();
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,64 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
@@ -120,4 +61,109 @@
|
||||
<data name="ApplicationName" xml:space="preserve">
|
||||
<value>Marechai.App-en</value>
|
||||
</data>
|
||||
<data name="News" xml:space="preserve">
|
||||
<value>News</value>
|
||||
</data>
|
||||
<data name="Books" xml:space="preserve">
|
||||
<value>Books</value>
|
||||
</data>
|
||||
<data name="Companies" xml:space="preserve">
|
||||
<value>Companies</value>
|
||||
</data>
|
||||
<data name="Computers" xml:space="preserve">
|
||||
<value>Computers</value>
|
||||
</data>
|
||||
<data name="Consoles" xml:space="preserve">
|
||||
<value>Consoles</value>
|
||||
</data>
|
||||
<data name="Documents" xml:space="preserve">
|
||||
<value>Documents</value>
|
||||
</data>
|
||||
<data name="Dumps" xml:space="preserve">
|
||||
<value>Dumps</value>
|
||||
</data>
|
||||
<data name="GraphicalProcessingUnits" xml:space="preserve">
|
||||
<value>Graphical Processing Units</value>
|
||||
</data>
|
||||
<data name="Magazines" xml:space="preserve">
|
||||
<value>Magazines</value>
|
||||
</data>
|
||||
<data name="People" xml:space="preserve">
|
||||
<value>People</value>
|
||||
</data>
|
||||
<data name="Processors" xml:space="preserve">
|
||||
<value>Processors</value>
|
||||
</data>
|
||||
<data name="Software" xml:space="preserve">
|
||||
<value>Software</value>
|
||||
</data>
|
||||
<data name="SoundSynthesizers" xml:space="preserve">
|
||||
<value>Sound Synthesizers</value>
|
||||
</data>
|
||||
<data name="Settings" xml:space="preserve">
|
||||
<value>Settings</value>
|
||||
</data>
|
||||
<data name="Login" xml:space="preserve">
|
||||
<value>Login</value>
|
||||
</data>
|
||||
<data name="Logout" xml:space="preserve">
|
||||
<value>Logout</value>
|
||||
</data>
|
||||
<data name="Company is active." xml:space="preserve">
|
||||
<value>Company is active.</value>
|
||||
</data>
|
||||
<data name="Company sold to {0} on {1}." xml:space="preserve">
|
||||
<value>Company sold to {0} on {1}.</value>
|
||||
</data>
|
||||
<data name="Company sold on {0} to an unknown company." xml:space="preserve">
|
||||
<value>Company sold on {0} to an unknown company.</value>
|
||||
</data>
|
||||
<data name="Company sold to {0} on an unknown date." xml:space="preserve">
|
||||
<value>Company sold to {0} on an unknown date.</value>
|
||||
</data>
|
||||
<data name="Company was sold to an unknown company on an unknown date." xml:space="preserve">
|
||||
<value>Company was sold to an unknown company on an unknown date.</value>
|
||||
</data>
|
||||
<data name="Company merged on {0} to form {1}." xml:space="preserve">
|
||||
<value>Company merged on {0} to form {1}.</value>
|
||||
</data>
|
||||
<data name="Company merged on {0} to form an unknown company." xml:space="preserve">
|
||||
<value>Company merged on {0} to form an unknown company.</value>
|
||||
</data>
|
||||
<data name="Company merged on an unknown date to form {0}." xml:space="preserve">
|
||||
<value>Company merged on an unknown date to form {0}.</value>
|
||||
</data>
|
||||
<data name="Company merged to form an unknown company on an unknown date." xml:space="preserve">
|
||||
<value>Company merged to form an unknown company on an unknown date.</value>
|
||||
</data>
|
||||
<data name="Current company status is unknown." xml:space="preserve">
|
||||
<value>Current company status is unknown.</value>
|
||||
</data>
|
||||
<data name="unknown date" xml:space="preserve">
|
||||
<value>unknown date</value>
|
||||
</data>
|
||||
<data name="Company declared bankruptcy on {0}." xml:space="preserve">
|
||||
<value>Company declared bankruptcy on {0}.</value>
|
||||
</data>
|
||||
<data name="Company declared bankruptcy on an unknown date." xml:space="preserve">
|
||||
<value>Company declared bankruptcy on an unknown date.</value>
|
||||
</data>
|
||||
<data name="Company ceased operations on {0}." xml:space="preserve">
|
||||
<value>Company ceased operations on {0}.</value>
|
||||
</data>
|
||||
<data name="Company ceased operations on an unknown date." xml:space="preserve">
|
||||
<value>Company ceased operations on an unknown date.</value>
|
||||
</data>
|
||||
<data name="Company renamed to {0} on {1}." xml:space="preserve">
|
||||
<value>Company renamed to {0} on {1}.</value>
|
||||
</data>
|
||||
<data name="Company was renamed on {0} to an unknown name." xml:space="preserve">
|
||||
<value>Company was renamed on {0} to an unknown name.</value>
|
||||
</data>
|
||||
<data name="Company renamed to {0} on an unknown date." xml:space="preserve">
|
||||
<value>Company renamed to {0} on an unknown date.</value>
|
||||
</data>
|
||||
<data name="Company was renamed on an unknown date to an unknown name." xml:space="preserve">
|
||||
<value>Company was renamed on an unknown date to an unknown name.</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -1,64 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
@@ -120,4 +61,109 @@
|
||||
<data name="ApplicationName" xml:space="preserve">
|
||||
<value>Marechai.App-es</value>
|
||||
</data>
|
||||
<data name="News" xml:space="preserve">
|
||||
<value>Noticias</value>
|
||||
</data>
|
||||
<data name="Books" xml:space="preserve">
|
||||
<value>Libros</value>
|
||||
</data>
|
||||
<data name="Companies" xml:space="preserve">
|
||||
<value>Empresas</value>
|
||||
</data>
|
||||
<data name="Computers" xml:space="preserve">
|
||||
<value>Computadoras</value>
|
||||
</data>
|
||||
<data name="Consoles" xml:space="preserve">
|
||||
<value>Consolas</value>
|
||||
</data>
|
||||
<data name="Documents" xml:space="preserve">
|
||||
<value>Documentos</value>
|
||||
</data>
|
||||
<data name="Dumps" xml:space="preserve">
|
||||
<value>Volcados</value>
|
||||
</data>
|
||||
<data name="GraphicalProcessingUnits" xml:space="preserve">
|
||||
<value>Unidades de Procesamiento Gráfico</value>
|
||||
</data>
|
||||
<data name="Magazines" xml:space="preserve">
|
||||
<value>Revistas</value>
|
||||
</data>
|
||||
<data name="People" xml:space="preserve">
|
||||
<value>Personas</value>
|
||||
</data>
|
||||
<data name="Processors" xml:space="preserve">
|
||||
<value>Procesadores</value>
|
||||
</data>
|
||||
<data name="Software" xml:space="preserve">
|
||||
<value>Software</value>
|
||||
</data>
|
||||
<data name="SoundSynthesizers" xml:space="preserve">
|
||||
<value>Sintetizadores de Sonido</value>
|
||||
</data>
|
||||
<data name="Settings" xml:space="preserve">
|
||||
<value>Configuración</value>
|
||||
</data>
|
||||
<data name="Login" xml:space="preserve">
|
||||
<value>Iniciar sesión</value>
|
||||
</data>
|
||||
<data name="Logout" xml:space="preserve">
|
||||
<value>Cerrar sesión</value>
|
||||
</data>
|
||||
<data name="Company is active." xml:space="preserve">
|
||||
<value>La empresa está activa.</value>
|
||||
</data>
|
||||
<data name="Company sold to {0} on {1}." xml:space="preserve">
|
||||
<value>La empresa fue vendida a {0} el {1}.</value>
|
||||
</data>
|
||||
<data name="Company sold on {0} to an unknown company." xml:space="preserve">
|
||||
<value>La empresa fue vendida el {0} a una empresa desconocida.</value>
|
||||
</data>
|
||||
<data name="Company sold to {0} on an unknown date." xml:space="preserve">
|
||||
<value>La empresa fue vendida a {0} en una fecha desconocida.</value>
|
||||
</data>
|
||||
<data name="Company was sold to an unknown company on an unknown date." xml:space="preserve">
|
||||
<value>La empresa fue vendida a una empresa desconocida en una fecha desconocida.</value>
|
||||
</data>
|
||||
<data name="Company merged on {0} to form {1}." xml:space="preserve">
|
||||
<value>La empresa se fusionó el {0} para formar {1}.</value>
|
||||
</data>
|
||||
<data name="Company merged on {0} to form an unknown company." xml:space="preserve">
|
||||
<value>La empresa se fusionó el {0} para formar una empresa desconocida.</value>
|
||||
</data>
|
||||
<data name="Company merged on an unknown date to form {0}." xml:space="preserve">
|
||||
<value>La empresa se fusionó en una fecha desconocida para formar {0}.</value>
|
||||
</data>
|
||||
<data name="Company merged to form an unknown company on an unknown date." xml:space="preserve">
|
||||
<value>La empresa se fusionó para formar una empresa desconocida en una fecha desconocida.</value>
|
||||
</data>
|
||||
<data name="Current company status is unknown." xml:space="preserve">
|
||||
<value>El estado actual de la empresa es desconocido.</value>
|
||||
</data>
|
||||
<data name="unknown date" xml:space="preserve">
|
||||
<value>fecha desconocida</value>
|
||||
</data>
|
||||
<data name="Company declared bankruptcy on {0}." xml:space="preserve">
|
||||
<value>La empresa declaró quiebra el {0}.</value>
|
||||
</data>
|
||||
<data name="Company declared bankruptcy on an unknown date." xml:space="preserve">
|
||||
<value>La empresa declaró quiebra en una fecha desconocida.</value>
|
||||
</data>
|
||||
<data name="Company ceased operations on {0}." xml:space="preserve">
|
||||
<value>La empresa cesó operaciones el {0}.</value>
|
||||
</data>
|
||||
<data name="Company ceased operations on an unknown date." xml:space="preserve">
|
||||
<value>La empresa cesó operaciones en una fecha desconocida.</value>
|
||||
</data>
|
||||
<data name="Company renamed to {0} on {1}." xml:space="preserve">
|
||||
<value>La empresa fue renombrada a {0} el {1}.</value>
|
||||
</data>
|
||||
<data name="Company was renamed on {0} to an unknown name." xml:space="preserve">
|
||||
<value>La empresa fue renombrada el {0} a un nombre desconocido.</value>
|
||||
</data>
|
||||
<data name="Company renamed to {0} on an unknown date." xml:space="preserve">
|
||||
<value>La empresa fue renombrada a {0} en una fecha desconocida.</value>
|
||||
</data>
|
||||
<data name="Company was renamed on an unknown date to an unknown name." xml:space="preserve">
|
||||
<value>La empresa fue renombrada en una fecha desconocida a un nombre desconocido.</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -1,64 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
@@ -120,4 +61,109 @@
|
||||
<data name="ApplicationName" xml:space="preserve">
|
||||
<value>Marechai.App-fr</value>
|
||||
</data>
|
||||
<data name="News" xml:space="preserve">
|
||||
<value>Actualités</value>
|
||||
</data>
|
||||
<data name="Books" xml:space="preserve">
|
||||
<value>Livres</value>
|
||||
</data>
|
||||
<data name="Companies" xml:space="preserve">
|
||||
<value>Entreprises</value>
|
||||
</data>
|
||||
<data name="Computers" xml:space="preserve">
|
||||
<value>Ordinateurs</value>
|
||||
</data>
|
||||
<data name="Consoles" xml:space="preserve">
|
||||
<value>Consoles</value>
|
||||
</data>
|
||||
<data name="Documents" xml:space="preserve">
|
||||
<value>Documents</value>
|
||||
</data>
|
||||
<data name="Dumps" xml:space="preserve">
|
||||
<value>Vidages</value>
|
||||
</data>
|
||||
<data name="GraphicalProcessingUnits" xml:space="preserve">
|
||||
<value>Processeurs Graphiques</value>
|
||||
</data>
|
||||
<data name="Magazines" xml:space="preserve">
|
||||
<value>Magazines</value>
|
||||
</data>
|
||||
<data name="People" xml:space="preserve">
|
||||
<value>Personnes</value>
|
||||
</data>
|
||||
<data name="Processors" xml:space="preserve">
|
||||
<value>Processeurs</value>
|
||||
</data>
|
||||
<data name="Software" xml:space="preserve">
|
||||
<value>Logiciels</value>
|
||||
</data>
|
||||
<data name="SoundSynthesizers" xml:space="preserve">
|
||||
<value>Synthétiseurs de Son</value>
|
||||
</data>
|
||||
<data name="Settings" xml:space="preserve">
|
||||
<value>Paramètres</value>
|
||||
</data>
|
||||
<data name="Login" xml:space="preserve">
|
||||
<value>Connexion</value>
|
||||
</data>
|
||||
<data name="Logout" xml:space="preserve">
|
||||
<value>Déconnexion</value>
|
||||
</data>
|
||||
<data name="Company is active." xml:space="preserve">
|
||||
<value>L'entreprise est active.</value>
|
||||
</data>
|
||||
<data name="Company sold to {0} on {1}." xml:space="preserve">
|
||||
<value>L'entreprise a été vendue à {0} le {1}.</value>
|
||||
</data>
|
||||
<data name="Company sold on {0} to an unknown company." xml:space="preserve">
|
||||
<value>L'entreprise a été vendue le {0} à une entreprise inconnue.</value>
|
||||
</data>
|
||||
<data name="Company sold to {0} on an unknown date." xml:space="preserve">
|
||||
<value>L'entreprise a été vendue à {0} à une date inconnue.</value>
|
||||
</data>
|
||||
<data name="Company was sold to an unknown company on an unknown date." xml:space="preserve">
|
||||
<value>L'entreprise a été vendue à une entreprise inconnue à une date inconnue.</value>
|
||||
</data>
|
||||
<data name="Company merged on {0} to form {1}." xml:space="preserve">
|
||||
<value>L'entreprise a fusionné le {0} pour former {1}.</value>
|
||||
</data>
|
||||
<data name="Company merged on {0} to form an unknown company." xml:space="preserve">
|
||||
<value>L'entreprise a fusionné le {0} pour former une entreprise inconnue.</value>
|
||||
</data>
|
||||
<data name="Company merged on an unknown date to form {0}." xml:space="preserve">
|
||||
<value>L'entreprise a fusionné à une date inconnue pour former {0}.</value>
|
||||
</data>
|
||||
<data name="Company merged to form an unknown company on an unknown date." xml:space="preserve">
|
||||
<value>L'entreprise a fusionné pour former une entreprise inconnue à une date inconnue.</value>
|
||||
</data>
|
||||
<data name="Current company status is unknown." xml:space="preserve">
|
||||
<value>L'état actuel de l'entreprise est inconnu.</value>
|
||||
</data>
|
||||
<data name="unknown date" xml:space="preserve">
|
||||
<value>date inconnue</value>
|
||||
</data>
|
||||
<data name="Company declared bankruptcy on {0}." xml:space="preserve">
|
||||
<value>L'entreprise a déclaré faillite le {0}.</value>
|
||||
</data>
|
||||
<data name="Company declared bankruptcy on an unknown date." xml:space="preserve">
|
||||
<value>L'entreprise a déclaré faillite à une date inconnue.</value>
|
||||
</data>
|
||||
<data name="Company ceased operations on {0}." xml:space="preserve">
|
||||
<value>L'entreprise a cessé ses activités le {0}.</value>
|
||||
</data>
|
||||
<data name="Company ceased operations on an unknown date." xml:space="preserve">
|
||||
<value>L'entreprise a cessé ses activités à une date inconnue.</value>
|
||||
</data>
|
||||
<data name="Company renamed to {0} on {1}." xml:space="preserve">
|
||||
<value>L'entreprise a été renommée en {0} le {1}.</value>
|
||||
</data>
|
||||
<data name="Company was renamed on {0} to an unknown name." xml:space="preserve">
|
||||
<value>L'entreprise a été renommée le {0} en un nom inconnu.</value>
|
||||
</data>
|
||||
<data name="Company renamed to {0} on an unknown date." xml:space="preserve">
|
||||
<value>L'entreprise a été renommée en {0} à une date inconnue.</value>
|
||||
</data>
|
||||
<data name="Company was renamed on an unknown date to an unknown name." xml:space="preserve">
|
||||
<value>L'entreprise a été renommée à une date inconnue en un nom inconnu.</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -1,64 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
@@ -120,4 +61,109 @@
|
||||
<data name="ApplicationName" xml:space="preserve">
|
||||
<value>Marechai.App-pt-BR</value>
|
||||
</data>
|
||||
<data name="News" xml:space="preserve">
|
||||
<value>Notícias</value>
|
||||
</data>
|
||||
<data name="Books" xml:space="preserve">
|
||||
<value>Livros</value>
|
||||
</data>
|
||||
<data name="Companies" xml:space="preserve">
|
||||
<value>Empresas</value>
|
||||
</data>
|
||||
<data name="Computers" xml:space="preserve">
|
||||
<value>Computadores</value>
|
||||
</data>
|
||||
<data name="Consoles" xml:space="preserve">
|
||||
<value>Consoles</value>
|
||||
</data>
|
||||
<data name="Documents" xml:space="preserve">
|
||||
<value>Documentos</value>
|
||||
</data>
|
||||
<data name="Dumps" xml:space="preserve">
|
||||
<value>Dumps</value>
|
||||
</data>
|
||||
<data name="GraphicalProcessingUnits" xml:space="preserve">
|
||||
<value>Unidades de Processamento Gráfico</value>
|
||||
</data>
|
||||
<data name="Magazines" xml:space="preserve">
|
||||
<value>Revistas</value>
|
||||
</data>
|
||||
<data name="People" xml:space="preserve">
|
||||
<value>Pessoas</value>
|
||||
</data>
|
||||
<data name="Processors" xml:space="preserve">
|
||||
<value>Processadores</value>
|
||||
</data>
|
||||
<data name="Software" xml:space="preserve">
|
||||
<value>Software</value>
|
||||
</data>
|
||||
<data name="SoundSynthesizers" xml:space="preserve">
|
||||
<value>Sintetizadores de Som</value>
|
||||
</data>
|
||||
<data name="Settings" xml:space="preserve">
|
||||
<value>Configurações</value>
|
||||
</data>
|
||||
<data name="Login" xml:space="preserve">
|
||||
<value>Fazer Login</value>
|
||||
</data>
|
||||
<data name="Logout" xml:space="preserve">
|
||||
<value>Fazer Logout</value>
|
||||
</data>
|
||||
<data name="Company is active." xml:space="preserve">
|
||||
<value>A empresa está ativa.</value>
|
||||
</data>
|
||||
<data name="Company sold to {0} on {1}." xml:space="preserve">
|
||||
<value>A empresa foi vendida para {0} em {1}.</value>
|
||||
</data>
|
||||
<data name="Company sold on {0} to an unknown company." xml:space="preserve">
|
||||
<value>A empresa foi vendida em {0} para uma empresa desconhecida.</value>
|
||||
</data>
|
||||
<data name="Company sold to {0} on an unknown date." xml:space="preserve">
|
||||
<value>A empresa foi vendida para {0} em uma data desconhecida.</value>
|
||||
</data>
|
||||
<data name="Company was sold to an unknown company on an unknown date." xml:space="preserve">
|
||||
<value>A empresa foi vendida para uma empresa desconhecida em uma data desconhecida.</value>
|
||||
</data>
|
||||
<data name="Company merged on {0} to form {1}." xml:space="preserve">
|
||||
<value>A empresa se fundiu em {0} para formar {1}.</value>
|
||||
</data>
|
||||
<data name="Company merged on {0} to form an unknown company." xml:space="preserve">
|
||||
<value>A empresa se fundiu em {0} para formar uma empresa desconhecida.</value>
|
||||
</data>
|
||||
<data name="Company merged on an unknown date to form {0}." xml:space="preserve">
|
||||
<value>A empresa se fundiu em uma data desconhecida para formar {0}.</value>
|
||||
</data>
|
||||
<data name="Company merged to form an unknown company on an unknown date." xml:space="preserve">
|
||||
<value>A empresa se fundiu para formar uma empresa desconhecida em uma data desconhecida.</value>
|
||||
</data>
|
||||
<data name="Current company status is unknown." xml:space="preserve">
|
||||
<value>O status atual da empresa é desconhecido.</value>
|
||||
</data>
|
||||
<data name="unknown date" xml:space="preserve">
|
||||
<value>data desconhecida</value>
|
||||
</data>
|
||||
<data name="Company declared bankruptcy on {0}." xml:space="preserve">
|
||||
<value>A empresa declarou falência em {0}.</value>
|
||||
</data>
|
||||
<data name="Company declared bankruptcy on an unknown date." xml:space="preserve">
|
||||
<value>A empresa declarou falência em uma data desconhecida.</value>
|
||||
</data>
|
||||
<data name="Company ceased operations on {0}." xml:space="preserve">
|
||||
<value>A empresa cessou operações em {0}.</value>
|
||||
</data>
|
||||
<data name="Company ceased operations on an unknown date." xml:space="preserve">
|
||||
<value>A empresa cessou operações em uma data desconhecida.</value>
|
||||
</data>
|
||||
<data name="Company renamed to {0} on {1}." xml:space="preserve">
|
||||
<value>A empresa foi renomeada para {0} em {1}.</value>
|
||||
</data>
|
||||
<data name="Company was renamed on {0} to an unknown name." xml:space="preserve">
|
||||
<value>A empresa foi renomeada em {0} para um nome desconhecido.</value>
|
||||
</data>
|
||||
<data name="Company renamed to {0} on an unknown date." xml:space="preserve">
|
||||
<value>A empresa foi renomeada para {0} em uma data desconhecida.</value>
|
||||
</data>
|
||||
<data name="Company was renamed on an unknown date to an unknown name." xml:space="preserve">
|
||||
<value>A empresa foi renomeada em uma data desconhecida para um nome desconhecido.</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
{
|
||||
"AppConfig": {
|
||||
"AppConfig": {
|
||||
"Environment": "Production"
|
||||
},
|
||||
"ApiClient": {
|
||||
"ApiClient": {
|
||||
"Url": "http://localhost:5023",
|
||||
"UseNativeHandler": true
|
||||
},
|
||||
"LocalizationConfiguration": {
|
||||
|
||||
@@ -52,19 +52,14 @@ public class MachineDto : BaseDto<int>
|
||||
[JsonPropertyName("family_name")]
|
||||
public string? FamilyName { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public List<GpuDto>? Gpus { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public List<MemoryDto>? Memory { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public List<ProcessorDto>? Processors { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public List<SoundSynthDto>? SoundSynthesizers { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public List<StorageDto>? Storage { get; set; }
|
||||
|
||||
[JsonPropertyName("company")]
|
||||
|
||||
@@ -40,13 +40,13 @@ namespace Marechai.Server.Controllers;
|
||||
[ApiController]
|
||||
public class ComputersController(MarechaiContext context) : ControllerBase
|
||||
{
|
||||
[HttpGet("/count")]
|
||||
[HttpGet("count")]
|
||||
[AllowAnonymous]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
public Task<int> GetComputersCountAsync() => context.Machines.CountAsync(c => c.Type == MachineType.Computer);
|
||||
|
||||
[HttpGet("/minimum-year")]
|
||||
[HttpGet("minimum-year")]
|
||||
[AllowAnonymous]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
@@ -56,7 +56,7 @@ public class ComputersController(MarechaiContext context) : ControllerBase
|
||||
t.Introduced.Value.Year > 1000)
|
||||
.MinAsync(t => t.Introduced.Value.Year);
|
||||
|
||||
[HttpGet("/maximum-year")]
|
||||
[HttpGet("maximum-year")]
|
||||
[AllowAnonymous]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
@@ -66,7 +66,7 @@ public class ComputersController(MarechaiContext context) : ControllerBase
|
||||
t.Introduced.Value.Year > 1000)
|
||||
.MaxAsync(t => t.Introduced.Value.Year);
|
||||
|
||||
[HttpGet("/by-letter/{c}")]
|
||||
[HttpGet("by-letter/{c}")]
|
||||
[AllowAnonymous]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
@@ -78,13 +78,14 @@ public class ComputersController(MarechaiContext context) : ControllerBase
|
||||
.ThenBy(m => m.Name)
|
||||
.Select(m => new MachineDto
|
||||
{
|
||||
Id = m.Id,
|
||||
Name = m.Name,
|
||||
Company = m.Company.Name
|
||||
Id = m.Id,
|
||||
Name = m.Name,
|
||||
Company = m.Company.Name,
|
||||
Introduced = m.Introduced
|
||||
})
|
||||
.ToListAsync();
|
||||
|
||||
[HttpGet("/by-year/{year:int}")]
|
||||
[HttpGet("by-year/{year:int}")]
|
||||
[AllowAnonymous]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
@@ -97,9 +98,10 @@ public class ComputersController(MarechaiContext context) : ControllerBase
|
||||
.ThenBy(m => m.Name)
|
||||
.Select(m => new MachineDto
|
||||
{
|
||||
Id = m.Id,
|
||||
Name = m.Name,
|
||||
Company = m.Company.Name
|
||||
Id = m.Id,
|
||||
Name = m.Name,
|
||||
Company = m.Company.Name,
|
||||
Introduced = m.Introduced
|
||||
})
|
||||
.ToListAsync();
|
||||
|
||||
@@ -113,9 +115,10 @@ public class ComputersController(MarechaiContext context) : ControllerBase
|
||||
.ThenBy(m => m.Name)
|
||||
.Select(m => new MachineDto
|
||||
{
|
||||
Id = m.Id,
|
||||
Name = m.Name,
|
||||
Company = m.Company.Name
|
||||
Id = m.Id,
|
||||
Name = m.Name,
|
||||
Company = m.Company.Name,
|
||||
Introduced = m.Introduced
|
||||
})
|
||||
.ToListAsync();
|
||||
}
|
||||
@@ -40,13 +40,13 @@ namespace Marechai.Server.Controllers;
|
||||
[ApiController]
|
||||
public class ConsolesController(MarechaiContext context) : ControllerBase
|
||||
{
|
||||
[HttpGet("/count")]
|
||||
[HttpGet("count")]
|
||||
[AllowAnonymous]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
public Task<int> GetConsolesCountAsync() => context.Machines.CountAsync(c => c.Type == MachineType.Console);
|
||||
|
||||
[HttpGet("/minimum-year")]
|
||||
[HttpGet("minimum-year")]
|
||||
[AllowAnonymous]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
@@ -56,7 +56,7 @@ public class ConsolesController(MarechaiContext context) : ControllerBase
|
||||
t.Introduced.Value.Year > 1000)
|
||||
.MinAsync(t => t.Introduced.Value.Year);
|
||||
|
||||
[HttpGet("/maximum-year")]
|
||||
[HttpGet("maximum-year")]
|
||||
[AllowAnonymous]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
@@ -66,7 +66,7 @@ public class ConsolesController(MarechaiContext context) : ControllerBase
|
||||
t.Introduced.Value.Year > 1000)
|
||||
.MaxAsync(t => t.Introduced.Value.Year);
|
||||
|
||||
[HttpGet("/by-letter/{c}")]
|
||||
[HttpGet("by-letter/{c}")]
|
||||
[AllowAnonymous]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
@@ -78,13 +78,14 @@ public class ConsolesController(MarechaiContext context) : ControllerBase
|
||||
.ThenBy(m => m.Name)
|
||||
.Select(m => new MachineDto
|
||||
{
|
||||
Id = m.Id,
|
||||
Name = m.Name,
|
||||
Company = m.Company.Name
|
||||
Id = m.Id,
|
||||
Name = m.Name,
|
||||
Company = m.Company.Name,
|
||||
Introduced = m.Introduced
|
||||
})
|
||||
.ToListAsync();
|
||||
|
||||
[HttpGet("/by-year/{year:int}")]
|
||||
[HttpGet("by-year/{year:int}")]
|
||||
[AllowAnonymous]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
@@ -97,9 +98,10 @@ public class ConsolesController(MarechaiContext context) : ControllerBase
|
||||
.ThenBy(m => m.Name)
|
||||
.Select(m => new MachineDto
|
||||
{
|
||||
Id = m.Id,
|
||||
Name = m.Name,
|
||||
Company = m.Company.Name
|
||||
Id = m.Id,
|
||||
Name = m.Name,
|
||||
Company = m.Company.Name,
|
||||
Introduced = m.Introduced
|
||||
})
|
||||
.ToListAsync();
|
||||
|
||||
@@ -113,9 +115,10 @@ public class ConsolesController(MarechaiContext context) : ControllerBase
|
||||
.ThenBy(m => m.Name)
|
||||
.Select(m => new MachineDto
|
||||
{
|
||||
Id = m.Id,
|
||||
Name = m.Name,
|
||||
Company = m.Company.Name
|
||||
Id = m.Id,
|
||||
Name = m.Name,
|
||||
Company = m.Company.Name,
|
||||
Introduced = m.Introduced
|
||||
})
|
||||
.ToListAsync();
|
||||
}
|
||||
@@ -40,13 +40,7 @@ namespace Marechai.Server.Controllers;
|
||||
|
||||
[Route("/machines")]
|
||||
[ApiController]
|
||||
public class MachinesController
|
||||
(
|
||||
MarechaiContext context,
|
||||
GpusController gpusController,
|
||||
ProcessorsController processorsController,
|
||||
SoundSynthsController soundSynthsController
|
||||
) : ControllerBase
|
||||
public class MachinesController(MarechaiContext context) : ControllerBase
|
||||
{
|
||||
[HttpGet]
|
||||
[AllowAnonymous]
|
||||
@@ -232,7 +226,25 @@ public class MachinesController
|
||||
model.FamilyId = family.Id;
|
||||
}
|
||||
|
||||
model.Gpus = await gpusController.GetByMachineAsync(machine.Id);
|
||||
model.Gpus = await context.GpusByMachine.Where(g => g.MachineId == machine.Id)
|
||||
.Select(g => g.Gpu)
|
||||
.OrderBy(g => g.Company.Name)
|
||||
.ThenBy(g => g.Name)
|
||||
.Select(g => new GpuDto
|
||||
{
|
||||
Id = g.Id,
|
||||
Name = g.Name,
|
||||
Company = g.Company.Name,
|
||||
CompanyId = g.Company.Id,
|
||||
ModelCode = g.ModelCode,
|
||||
Introduced = g.Introduced,
|
||||
Package = g.Package,
|
||||
Process = g.Process,
|
||||
ProcessNm = g.ProcessNm,
|
||||
DieSize = g.DieSize,
|
||||
Transistors = g.Transistors
|
||||
})
|
||||
.ToListAsync();
|
||||
|
||||
model.Memory = await context.MemoryByMachine.Where(m => m.MachineId == machine.Id)
|
||||
.Select(m => new MemoryDto
|
||||
@@ -244,9 +256,63 @@ public class MachinesController
|
||||
})
|
||||
.ToListAsync();
|
||||
|
||||
model.Processors = await processorsController.GetByMachineAsync(machine.Id);
|
||||
model.Processors = await context.ProcessorsByMachine.Where(p => p.MachineId == machine.Id)
|
||||
.Select(p => new ProcessorDto
|
||||
{
|
||||
Name = p.Processor.Name,
|
||||
CompanyName = p.Processor.Company.Name,
|
||||
CompanyId = p.Processor.Company.Id,
|
||||
ModelCode = p.Processor.ModelCode,
|
||||
Introduced = p.Processor.Introduced,
|
||||
Speed = p.Speed,
|
||||
Package = p.Processor.Package,
|
||||
Gprs = p.Processor.Gprs,
|
||||
GprSize = p.Processor.GprSize,
|
||||
Fprs = p.Processor.Fprs,
|
||||
FprSize = p.Processor.FprSize,
|
||||
Cores = p.Processor.Cores,
|
||||
ThreadsPerCore = p.Processor.ThreadsPerCore,
|
||||
Process = p.Processor.Process,
|
||||
ProcessNm = p.Processor.ProcessNm,
|
||||
DieSize = p.Processor.DieSize,
|
||||
Transistors = p.Processor.Transistors,
|
||||
DataBus = p.Processor.DataBus,
|
||||
AddrBus = p.Processor.AddrBus,
|
||||
SimdRegisters = p.Processor.SimdRegisters,
|
||||
SimdSize = p.Processor.SimdSize,
|
||||
L1Instruction = p.Processor.L1Instruction,
|
||||
L1Data = p.Processor.L1Data,
|
||||
L2 = p.Processor.L2,
|
||||
L3 = p.Processor.L3,
|
||||
InstructionSet = p.Processor.InstructionSet.Name,
|
||||
Id = p.Processor.Id,
|
||||
InstructionSetExtensions = p.Processor.InstructionSetExtensions
|
||||
.Select(e => e.Extension.Extension)
|
||||
.ToList()
|
||||
})
|
||||
.ToListAsync();
|
||||
|
||||
model.SoundSynthesizers = await soundSynthsController.GetByMachineAsync(machine.Id);
|
||||
model.SoundSynthesizers = await context.SoundByMachine.Where(s => s.MachineId == machine.Id)
|
||||
.Select(s => s.SoundSynth)
|
||||
.OrderBy(s => s.Company.Name)
|
||||
.ThenBy(s => s.Name)
|
||||
.ThenBy(s => s.ModelCode)
|
||||
.Select(s => new SoundSynthDto
|
||||
{
|
||||
Id = s.Id,
|
||||
Name = s.Name,
|
||||
CompanyId = s.Company.Id,
|
||||
CompanyName = s.Company.Name,
|
||||
ModelCode = s.ModelCode,
|
||||
Introduced = s.Introduced,
|
||||
Voices = s.Voices,
|
||||
Frequency = s.Frequency,
|
||||
Depth = s.Depth,
|
||||
SquareWave = s.SquareWave,
|
||||
WhiteNoise = s.WhiteNoise,
|
||||
Type = s.Type
|
||||
})
|
||||
.ToListAsync();
|
||||
|
||||
model.Storage = await context.StorageByMachine.Where(s => s.MachineId == machine.Id)
|
||||
.Select(s => new StorageDto
|
||||
|
||||
@@ -210,24 +210,19 @@ file class Program
|
||||
builder.Services.AddScoped<TokenService, TokenService>();
|
||||
|
||||
// Read allowed CORS origins from configuration
|
||||
string[] allowedOrigins = builder.Configuration.GetSection("CORS:AllowedOrigins").Get<string[]>();
|
||||
string[] allowedOrigins = builder.Configuration.GetSection("CORS:AllowedOrigins").Get<string[]>() ??
|
||||
Array.Empty<string>();
|
||||
|
||||
builder.Services.AddCors(options =>
|
||||
{
|
||||
options.AddPolicy("AllowFrontend",
|
||||
policy =>
|
||||
{
|
||||
switch(allowedOrigins)
|
||||
{
|
||||
case ["*"]:
|
||||
policy.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod();
|
||||
|
||||
break;
|
||||
case { Length: > 0 }:
|
||||
policy.WithOrigins(allowedOrigins).AllowAnyHeader().AllowAnyMethod();
|
||||
|
||||
break;
|
||||
}
|
||||
// Check if wildcard is in the allowed origins
|
||||
if(allowedOrigins.Contains("*"))
|
||||
policy.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod();
|
||||
else if(allowedOrigins.Length > 0)
|
||||
policy.WithOrigins(allowedOrigins).AllowAnyHeader().AllowAnyMethod();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user