refacts and PostIt Nav
This commit is contained in:
parent
1a0556695c
commit
e98bba4247
34 changed files with 315 additions and 200 deletions
|
|
@ -10,6 +10,7 @@
|
|||
<PackageVersion Include="Microsoft.AspNetCore.Http.Features" Version="5.0.17" />
|
||||
<PackageVersion Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="10.0.9" />
|
||||
<PackageVersion Include="Microsoft.AspNetCore.Identity.UI" Version="10.0.9" />
|
||||
<PackageVersion Include="Microsoft.AspNetCore.Mvc.DataAnnotations" Version="2.3.11" />
|
||||
<PackageVersion Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="10.0.9" />
|
||||
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="10.0.9" />
|
||||
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.9" />
|
||||
|
|
@ -24,7 +25,6 @@
|
|||
<PackageVersion Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="10.0.9" />
|
||||
<PackageVersion Include="System.Security.Cryptography.Pkcs" Version="10.0.9" />
|
||||
<PackageVersion Include="Microsoft.AspNetCore.Authentication" Version="10.0.8" />
|
||||
|
||||
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="8.19.1" />
|
||||
<PackageVersion Include="Microsoft.AspNetCore.Antiforgery" Version="2.3.11" />
|
||||
<PackageVersion Include="Microsoft.AspNetCore.Razor" Version="2.3.0" />
|
||||
|
|
@ -34,10 +34,8 @@
|
|||
<PackageVersion Include="Microsoft.Extensions.CommandLineUtils" Version="1.1.1" />
|
||||
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.6.0" />
|
||||
<PackageVersion Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="10.0.2" />
|
||||
|
||||
<PackageVersion Include="Google.Apis.Calendar.v3" Version="1.74.0.4154" />
|
||||
<PackageVersion Include="Google.Apis.Compute.v1" Version="1.75.0.4157" />
|
||||
|
||||
<PackageVersion Include="IdentityModel.AspNetCore" Version="4.3.0" />
|
||||
<PackageVersion Include="IdentityModel.OidcClient" Version="6.0.0" />
|
||||
<PackageVersion Include="HigginsSoft.IdentityServer8" Version="8.0.5-preview-net9" />
|
||||
|
|
@ -46,12 +44,9 @@
|
|||
<PackageVersion Include="HigginsSoft.IdentityServer8.EntityFramework.Storage" Version="8.0.5-preview-net9" />
|
||||
<PackageVersion Include="HigginsSoft.IdentityServer8.Security" Version="8.0.5-preview-net9" />
|
||||
<PackageVersion Include="HigginsSoft.IdentityServer8.Storage" Version="8.0.5-preview-net9" />
|
||||
|
||||
|
||||
<PackageVersion Include="Anthropic.SDK" Version="5.10.0" />
|
||||
<PackageVersion Include="AsciiDocSharp" Version="0.2.0" />
|
||||
<PackageVersion Include="AsciiDocSharp.Converters.Html" Version="0.2.0" />
|
||||
|
||||
<PackageVersion Include="Avalonia" Version="12.0.4" />
|
||||
<PackageVersion Include="Avalonia.AvaloniaEdit" Version="12.0.0" />
|
||||
<PackageVersion Include="Avalonia.Desktop" Version="12.0.4" />
|
||||
|
|
@ -60,16 +55,14 @@
|
|||
<PackageVersion Include="Avalonia.Browser" Version="12.0.4" />
|
||||
<PackageVersion Include="Avalonia.Android" Version="12.0.4" />
|
||||
<PackageVersion Include="AvaloniaUI.DiagnosticsSupport" Version="2.2.2" />
|
||||
|
||||
<PackageVersion Include="bootstrap" Version="5.3.8" />
|
||||
<PackageVersion Include="Xamarin.AndroidX.Core.SplashScreen" Version="1.2.0" />
|
||||
<PackageVersion Include="CommunityToolkit.Mvvm" Version="8.4.2" />
|
||||
<PackageVersion Include="coverlet.collector" Version="10.0.1" />
|
||||
|
||||
<PackageVersion Include="Magick.NET-Q8-AnyCPU" Version="14.14.0" />
|
||||
<PackageVersion Include="MailKit" Version="4.17.0" />
|
||||
<PackageVersion Include="MimeKit" Version="4.17.0" />
|
||||
<PackageVersion Include="Newtonsoft.Json" Version="13.0.4" />
|
||||
<PackageVersion Include="Json.NET" Version="1.0.33" />
|
||||
<PackageVersion Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="10.0.2" />
|
||||
<PackageVersion Include="PayPalMerchantSDK" Version="2.16.250" />
|
||||
<PackageVersion Include="pazof.rules" Version="1.1.3" />
|
||||
|
|
@ -81,6 +74,5 @@
|
|||
<PackageVersion Include="Swashbuckle.AspNetCore" Version="10.2.1" />
|
||||
<PackageVersion Include="xunit" Version="2.9.3" />
|
||||
<PackageVersion Include="xunit.runner.visualstudio" Version="3.1.5" />
|
||||
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
@ -27,18 +27,18 @@ public partial class App : Application
|
|||
{
|
||||
desktop.MainWindow = new MainWindow
|
||||
{
|
||||
DataContext = new MainViewModel()
|
||||
DataContext = new MainPageViewModel()
|
||||
};
|
||||
}
|
||||
else if (ApplicationLifetime is IActivityApplicationLifetime singleViewFactoryApplicationLifetime)
|
||||
{
|
||||
singleViewFactoryApplicationLifetime.MainViewFactory = () => new MainView { DataContext = new MainViewModel() };
|
||||
singleViewFactoryApplicationLifetime.MainViewFactory = () => new MainPage { DataContext = new MainPageViewModel() };
|
||||
}
|
||||
else if (ApplicationLifetime is ISingleViewApplicationLifetime singleViewPlatform)
|
||||
{
|
||||
singleViewPlatform.MainView = new MainView
|
||||
singleViewPlatform.MainView = new MainPage
|
||||
{
|
||||
DataContext = new MainViewModel()
|
||||
DataContext = new MainPageViewModel()
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ public partial class Settings : ObservableObject
|
|||
|
||||
|
||||
[ObservableProperty]
|
||||
public partial string[] Scopes { get; set; }
|
||||
public partial string[] Scopes { get; set; }
|
||||
|
||||
internal OidcClientOptions GetOidcClientOptions()
|
||||
{
|
||||
|
|
@ -40,20 +40,24 @@ public partial class Settings : ObservableObject
|
|||
|
||||
}
|
||||
|
||||
internal async Task Load(IStorageProvider storageProvider)
|
||||
internal async Task Load()
|
||||
{
|
||||
var configFile = await storageProvider.TryGetFileFromPathAsync(
|
||||
Path.Combine(AppContext.BaseDirectory, SettingsFileName));
|
||||
String configPath =
|
||||
Path.Combine(AppContext.BaseDirectory, SettingsFileName);
|
||||
|
||||
if (configFile is null)
|
||||
FileInfo configFileInfo = new FileInfo(configPath);
|
||||
|
||||
if (!configFileInfo.Exists)
|
||||
{
|
||||
Console.Error.WriteLine("🩎 No settings file found.");
|
||||
Console.Error.WriteLine($"🩎 Settings file not found at {configFileInfo.FullName}");
|
||||
return; // no settings file
|
||||
}
|
||||
try {
|
||||
using var stream = await configFile.OpenReadAsync();
|
||||
|
||||
Console.WriteLine($"🔎 Loading settings from {configFileInfo.FullName}");
|
||||
|
||||
try
|
||||
{
|
||||
using var stream = configFileInfo.OpenRead();
|
||||
using var reader = new StreamReader(stream);
|
||||
var json = await reader.ReadToEndAsync();
|
||||
if (string.IsNullOrWhiteSpace(json))
|
||||
|
|
@ -74,7 +78,6 @@ public partial class Settings : ObservableObject
|
|||
this.ApiUrl = settings.ApiUrl;
|
||||
this.Scopes = settings.Scopes;
|
||||
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,36 +2,34 @@ using System;
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Templates;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using PostIt.ViewModels;
|
||||
using PostIt.Views;
|
||||
|
||||
namespace PostIt;
|
||||
|
||||
/// <summary>
|
||||
/// Given a view model, returns the corresponding view if possible.
|
||||
/// </summary>
|
||||
[RequiresUnreferencedCode(
|
||||
"Default implementation of ViewLocator involves reflection which may be trimmed away.",
|
||||
Url = "https://docs.avaloniaui.net/docs/concepts/view-locator")]
|
||||
|
||||
public class ViewLocator : IDataTemplate
|
||||
{
|
||||
public Control? Build(object? param)
|
||||
private readonly IServiceProvider _services;
|
||||
|
||||
public ViewLocator(IServiceProvider services)
|
||||
{
|
||||
if (param is null)
|
||||
return null;
|
||||
_services = services;
|
||||
}
|
||||
|
||||
var name = param.GetType().FullName!.Replace("ViewModel", "View", StringComparison.Ordinal);
|
||||
var type = Type.GetType(name);
|
||||
|
||||
if (type != null)
|
||||
public Control Build(object data)
|
||||
{
|
||||
return (Control)Activator.CreateInstance(type)!;
|
||||
}
|
||||
|
||||
return new TextBlock { Text = "Not Found: " + name };
|
||||
}
|
||||
|
||||
public bool Match(object? data)
|
||||
return data switch
|
||||
{
|
||||
return data is ViewModelBase;
|
||||
MainPageViewModel => _services.GetRequiredService<MainPage>(),
|
||||
SettingsPageViewModel => _services.GetRequiredService<SettingsPage>(),
|
||||
_ => new TextBlock { Text = $"No view for {data.GetType().Name}" }
|
||||
};
|
||||
}
|
||||
|
||||
public bool Match(object data) => data is ViewModelBase;
|
||||
}
|
||||
15
src/PostIt/PostIt/ViewModels/HomePageViewModel.cs
Normal file
15
src/PostIt/PostIt/ViewModels/HomePageViewModel.cs
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
|
||||
namespace PostIt.ViewModels;
|
||||
|
||||
public class HomePageViewModel : ViewModelBase
|
||||
{
|
||||
private string _welcomeText = "Welcome to PostIt!";
|
||||
public string WelcomeText
|
||||
{
|
||||
get => _welcomeText;
|
||||
set => SetProperty(ref _welcomeText, value);
|
||||
}
|
||||
public override bool CanNavigateNext { get => true; protected set => throw new System.NotImplementedException(); }
|
||||
public override bool CanNavigatePrevious { get => false; protected set => throw new System.NotImplementedException(); }
|
||||
|
||||
}
|
||||
|
|
@ -15,9 +15,15 @@ using Avalonia.Styling;
|
|||
|
||||
namespace PostIt.ViewModels;
|
||||
|
||||
public partial class MainViewModel : ViewModelBase
|
||||
public partial class MainPageViewModel : ViewModelBase
|
||||
{
|
||||
|
||||
[ObservableProperty]
|
||||
public partial string Title { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial ViewModelBase? CurrentViewModel { get; set; }
|
||||
public SettingsPageViewModel SettingsModel { get; }
|
||||
[ObservableProperty]
|
||||
public partial string StatusMessage { get; set; }
|
||||
|
||||
|
|
@ -44,8 +50,10 @@ public partial class MainViewModel : ViewModelBase
|
|||
|
||||
[ObservableProperty]
|
||||
public partial Settings Settings { get; private set; }
|
||||
public override bool CanNavigateNext { get => throw new NotImplementedException(); protected set => throw new NotImplementedException(); }
|
||||
public override bool CanNavigatePrevious { get => throw new NotImplementedException(); protected set => throw new NotImplementedException(); }
|
||||
|
||||
public MainViewModel()
|
||||
public MainPageViewModel()
|
||||
{
|
||||
SearchText = string.Empty;
|
||||
Posts = new ObservableCollection<BlogPost>();
|
||||
|
|
@ -55,6 +63,9 @@ public partial class MainViewModel : ViewModelBase
|
|||
IsBusy = false;
|
||||
StatusMessage = "Ready";
|
||||
Settings = new Settings();
|
||||
Title = "PostIt";
|
||||
CurrentViewModel = this;
|
||||
SettingsModel = new SettingsPageViewModel();
|
||||
}
|
||||
|
||||
partial void OnSearchTextChanged(string value)
|
||||
|
|
@ -105,7 +116,7 @@ public partial class MainViewModel : ViewModelBase
|
|||
try
|
||||
{
|
||||
|
||||
var loginWin = new PostIt.Views.LoginWindow();
|
||||
var loginWin = new PostIt.Views.LoginPage();
|
||||
var result = await loginWin.StartLoginAsync(Settings.GetOidcClientOptions());
|
||||
|
||||
if (result is not null && !result.IsError && !string.IsNullOrWhiteSpace(result.AccessToken))
|
||||
|
|
@ -202,6 +213,12 @@ public partial class MainViewModel : ViewModelBase
|
|||
StatusMessage = "New blog post ready.";
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
internal void OpenSettings()
|
||||
{
|
||||
// Appeler la méthode OpenSettings de la vue MainWindow
|
||||
CurrentViewModel = SettingsModel;
|
||||
}
|
||||
|
||||
private async Task RefreshPostsAsync()
|
||||
{
|
||||
|
|
@ -299,6 +316,7 @@ public partial class MainViewModel : ViewModelBase
|
|||
return payload;
|
||||
}
|
||||
|
||||
|
||||
private static readonly JsonSerializerOptions JsonOptions = new()
|
||||
{
|
||||
PropertyNameCaseInsensitive = true
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ using CommunityToolkit.Mvvm.ComponentModel;
|
|||
|
||||
namespace PostIt.ViewModels;
|
||||
|
||||
public partial class SettingsViewModel : ViewModelBase
|
||||
public partial class SettingsPageViewModel : ViewModelBase
|
||||
{
|
||||
[ObservableProperty]
|
||||
public partial bool DarkMode { get; set; }
|
||||
|
|
@ -15,5 +15,6 @@ public partial class SettingsViewModel : ViewModelBase
|
|||
|
||||
[ObservableProperty]
|
||||
public partial string ClientSecret { get; set; }
|
||||
|
||||
public override bool CanNavigateNext { get => false; protected set => throw new System.NotImplementedException(); }
|
||||
public override bool CanNavigatePrevious { get => true; protected set => throw new System.NotImplementedException(); }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,4 +5,15 @@ namespace PostIt.ViewModels;
|
|||
|
||||
public abstract partial class ViewModelBase : ObservableObject
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Gets if the user can navigate to the next page
|
||||
/// </summary>
|
||||
public abstract bool CanNavigateNext { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets if the user can navigate to the previous page
|
||||
/// </summary>
|
||||
public abstract bool CanNavigatePrevious { get; protected set; }
|
||||
|
||||
}
|
||||
|
|
|
|||
16
src/PostIt/PostIt/Views/HomePage.axaml
Normal file
16
src/PostIt/PostIt/Views/HomePage.axaml
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
<ContentPage xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
x:Class="PostIt.Views.HomePage"
|
||||
Header="Home">
|
||||
<StackPanel HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Spacing="12">
|
||||
<TextBlock Text="Welcome to the Home Page"
|
||||
FontSize="22"
|
||||
FontWeight="SemiBold"
|
||||
HorizontalAlignment="Center"/>
|
||||
<Button Content="Login"
|
||||
Click="OnLoginClick"
|
||||
HorizontalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
</ContentPage>
|
||||
23
src/PostIt/PostIt/Views/HomePage.axaml.cs
Normal file
23
src/PostIt/PostIt/Views/HomePage.axaml.cs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PostIt.Views;
|
||||
|
||||
public partial class HomePage : ContentPage
|
||||
{
|
||||
public HomePage()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private async void OnLoginClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (Navigation is not null)
|
||||
|
||||
await Navigation.PushModalAsync(new LoginPage());
|
||||
}
|
||||
|
||||
}
|
||||
37
src/PostIt/PostIt/Views/LoginPage.axaml
Normal file
37
src/PostIt/PostIt/Views/LoginPage.axaml
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
<ContentPage xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
x:Class="PostIt.Views.LoginPage"
|
||||
Header="Login">
|
||||
|
||||
<StackPanel HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Spacing="20">
|
||||
|
||||
<TextBlock Text="Sign In"
|
||||
FontSize="24"
|
||||
HorizontalAlignment="Center"/>
|
||||
|
||||
<StackPanel Spacing="4">
|
||||
<TextBlock Text="Email"/>
|
||||
<TextBox Name="EmailBox"
|
||||
PlaceholderText="Enter your email"/>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Spacing="4">
|
||||
<TextBlock Text="Password"/>
|
||||
<TextBox Name="PasswordBox"
|
||||
PlaceholderText="Enter your password"
|
||||
PasswordChar="•"/>
|
||||
</StackPanel>
|
||||
|
||||
<Button Content="Login"
|
||||
Click="OnLoginClick"/>
|
||||
|
||||
<Button Content="Cancel"
|
||||
Click="OnCancelClick"/>
|
||||
|
||||
<TextBlock Name="StatusText" Text="Starting authentication..." />
|
||||
<ProgressBar IsIndeterminate="True" />
|
||||
|
||||
</StackPanel>
|
||||
</ContentPage>
|
||||
51
src/PostIt/PostIt/Views/LoginPage.axaml.cs
Normal file
51
src/PostIt/PostIt/Views/LoginPage.axaml.cs
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using IdentityModel.OidcClient;
|
||||
using PostIt.Services;
|
||||
|
||||
namespace PostIt.Views;
|
||||
|
||||
public partial class LoginPage : ContentPage
|
||||
{
|
||||
private TaskCompletionSource<LoginResult?> _tcs = new();
|
||||
|
||||
public Settings Settings { get; }
|
||||
|
||||
public LoginPage()
|
||||
{
|
||||
this.Settings = new Settings();
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public async Task<LoginResult?> StartLoginAsync(OidcClientOptions options)
|
||||
{
|
||||
try
|
||||
{
|
||||
Settings.Load().Wait();
|
||||
|
||||
var client = new OidcClient(options);
|
||||
var loginResult = await client.LoginAsync(new LoginRequest());
|
||||
return loginResult;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private async void OnLoginClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
// This is where you specify your actual login auth logic
|
||||
if (Navigation is not null)
|
||||
await Navigation.PopModalAsync();
|
||||
}
|
||||
|
||||
private async void OnCancelClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
// Cancel button dismisses all open modals
|
||||
if (Navigation is not null)
|
||||
await Navigation.PopAllModalsAsync();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
<Window xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
x:Class="PostIt.Views.LoginWindow"
|
||||
Width="480" Height="160" WindowStartupLocation="CenterOwner"
|
||||
Title="Login">
|
||||
<StackPanel Margin="12" Spacing="12">
|
||||
<TextBlock Name="StatusText" Text="Starting authentication..." />
|
||||
<ProgressBar IsIndeterminate="True" />
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
|
||||
<Button Name="CancelButton" Content="Cancel" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Window>
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using IdentityModel.OidcClient;
|
||||
using PostIt.Services;
|
||||
|
||||
namespace PostIt.Views;
|
||||
|
||||
public partial class LoginWindow : Window
|
||||
{
|
||||
private TaskCompletionSource<LoginResult?> _tcs = new();
|
||||
|
||||
public LoginWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
CancelButton.Click += (_, __) => Close(null);
|
||||
}
|
||||
|
||||
public async Task<LoginResult?> StartLoginAsync(OidcClientOptions options)
|
||||
{
|
||||
try
|
||||
{
|
||||
var client = new OidcClient(options);
|
||||
var loginResult = await client.LoginAsync(new LoginRequest());
|
||||
return loginResult;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
<NavigationPage xmlns="https://github.com/avaloniaui"
|
||||
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"
|
||||
|
|
@ -6,17 +6,16 @@
|
|||
xmlns:models="using:PostIt.Models"
|
||||
xmlns:views="using:PostIt.Views"
|
||||
xmlns:AvaloniaEdit="clr-namespace:AvaloniaEdit;assembly=AvaloniaEdit"
|
||||
mc:Ignorable="d" d:DesignWidth="900" d:DesignHeight="600"
|
||||
x:Class="PostIt.Views.MainView"
|
||||
x:DataType="vm:MainViewModel">
|
||||
mc:Ignorable="d"
|
||||
x:Class="PostIt.Views.MainPage"
|
||||
x:DataType="vm:MainPageViewModel" HorizontalAlignment="Center" VerticalAlignment="Center" >
|
||||
<Design.DataContext>
|
||||
<vm:MainViewModel />
|
||||
<vm:MainPageViewModel />
|
||||
</Design.DataContext>
|
||||
|
||||
<StackPanel Margin="12" Spacing="12">
|
||||
<StackPanel Margin="12" Spacing="12" HorizontalAlignment="Center" >
|
||||
<TextBlock Text="PostIt Blog API Interface" FontSize="20" FontWeight="Bold" />
|
||||
|
||||
|
||||
<StackPanel Orientation="Horizontal" Spacing="8" >
|
||||
<Button Command="{Binding Login}" Content="Acquire token" />
|
||||
<Button Command="{Binding LoadPosts}" Content="Load posts" />
|
||||
|
|
@ -26,7 +25,6 @@
|
|||
<Button Command="{Binding Delete}" Content="Delete" />
|
||||
</StackPanel>
|
||||
|
||||
<Grid ColumnDefinitions="2*,3*" RowDefinitions="*" ColumnSpacing="12">
|
||||
<Border BorderBrush="Gray" BorderThickness="1" Padding="8">
|
||||
<ListBox ItemsSource="{Binding FilteredPosts}" SelectedItem="{Binding SelectedPost, Mode=TwoWay}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
|
||||
<ListBox.ItemTemplate>
|
||||
|
|
@ -56,6 +54,6 @@
|
|||
<TextBlock Text="{Binding StatusMessage}" Foreground="Gray" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
</NavigationPage>
|
||||
|
|
@ -4,9 +4,9 @@ using Avalonia.Controls;
|
|||
|
||||
namespace PostIt.Views;
|
||||
|
||||
public partial class MainView : UserControl
|
||||
public partial class MainPage : NavigationPage
|
||||
{
|
||||
public MainView()
|
||||
public MainPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
26
src/PostIt/PostIt/Views/MainViewModel.cs
Normal file
26
src/PostIt/PostIt/Views/MainViewModel.cs
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using PostIt.ViewModels;
|
||||
|
||||
public partial class MainWindowViewModel : ObservableObject
|
||||
{
|
||||
// Stocke le ViewModel de la page actuellement affichée
|
||||
[ObservableProperty]
|
||||
private object? _currentPage;
|
||||
|
||||
// Instances des pages pour éviter de les recréer à chaque fois (Optionnel)
|
||||
private readonly HomePageViewModel _homePage = new();
|
||||
private readonly SettingsPageViewModel _settingsPage = new();
|
||||
|
||||
public MainWindowViewModel()
|
||||
{
|
||||
// Définir la page de démarrage par défaut
|
||||
CurrentPage = _homePage;
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void NavigateToHome() => CurrentPage = _homePage;
|
||||
|
||||
[RelayCommand]
|
||||
private void NavigateToSettings() => CurrentPage = _settingsPage;
|
||||
}
|
||||
|
|
@ -1,13 +1,14 @@
|
|||
<Window xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:vm="using:PostIt.ViewModels"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:views="using:PostIt.Views"
|
||||
x:DataType="vm:MainPageViewModel"
|
||||
x:Class="PostIt.Views.MainWindow"
|
||||
x:DataType="vm:MainViewModel"
|
||||
Icon="/Assets/yavsc-logo.ico"
|
||||
Title="PostIt"
|
||||
>
|
||||
<views:MainView x:Name="MainView"/>
|
||||
|
||||
<!-- Association des ViewModels aux Vues graphiques (UserControls) -->
|
||||
<NavigationPage>
|
||||
<views:HomePage/>
|
||||
</NavigationPage>
|
||||
|
||||
</Window>
|
||||
|
|
|
|||
|
|
@ -1,35 +1,11 @@
|
|||
using Avalonia.Controls;
|
||||
using Avalonia.Styling;
|
||||
using PostIt.ViewModels;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PostIt.Views;
|
||||
|
||||
public partial class MainWindow : Window
|
||||
{
|
||||
internal Settings Settings { get; private set; }
|
||||
|
||||
public MainWindow()
|
||||
{
|
||||
|
||||
InitializeComponent();
|
||||
|
||||
this.Settings = new Settings();
|
||||
|
||||
|
||||
}
|
||||
|
||||
protected override void OnDataContextChanged(EventArgs e)
|
||||
{
|
||||
base.OnDataContextChanged(e);
|
||||
if (DataContext is MainViewModel vm)
|
||||
{
|
||||
Task.Run(async () => await this.Settings.Load(this.StorageProvider)).Wait();
|
||||
this.RequestedThemeVariant = Settings.DarkMode ? ThemeVariant.Dark : ThemeVariant.Light;
|
||||
MainView.DataContext = new MainViewModel();
|
||||
vm.Settings.Load(this.StorageProvider).Wait();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,11 +1,10 @@
|
|||
<Window
|
||||
<ContentPage
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="cl:avalonia.Controls"
|
||||
x:Class="PostIt.Views.SettingsView"
|
||||
x:Class="PostIt.Views.SettingsPage"
|
||||
xmlns:vm="using:PostIt.ViewModels"
|
||||
x:DataType="vm:SettingsViewModel"
|
||||
Title="Settings"
|
||||
x:DataType="vm:SettingsPageViewModel"
|
||||
Width="400"
|
||||
Height="300">
|
||||
<Grid>
|
||||
|
|
@ -26,4 +25,4 @@
|
|||
<TextBlock Grid.Row="4" Text="ClientSecret"/>
|
||||
<TextBox Grid.Row="5" x:Name="ClientSecretTextBox" Text="{Binding ClientSecret, Mode=TwoWay}"/>
|
||||
</Grid>
|
||||
</Window>
|
||||
</ContentPage>
|
||||
|
|
@ -3,9 +3,9 @@
|
|||
using Avalonia.Controls;
|
||||
|
||||
namespace PostIt.Views;
|
||||
public partial class SettingsView: Window
|
||||
public partial class SettingsPage: ContentPage
|
||||
{
|
||||
public SettingsView()
|
||||
public SettingsPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
|
@ -7,8 +7,8 @@ namespace Yavsc
|
|||
{
|
||||
public interface IBlogPostPayLoad
|
||||
{
|
||||
string? Article { get; set; }
|
||||
string? Photo { get; set; }
|
||||
string Article { get; set; }
|
||||
string Photo { get; set; }
|
||||
|
||||
}
|
||||
public interface IBlogPost : IBlogPostPayLoad, ITrackedEntity, IIdentified<long>, ITitle
|
||||
|
|
|
|||
|
|
@ -7,10 +7,12 @@ namespace Yavsc.Models.FileSystem
|
|||
{
|
||||
[ValidRemoteUserFilePath]
|
||||
[StringLength(512)]
|
||||
[Required]
|
||||
public required string Id { get; set; }
|
||||
|
||||
[StringLength(512)]
|
||||
[ValidRemoteUserFilePath]
|
||||
[Required]
|
||||
public required string To { get; set; }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Yavsc.Abstract.IT {
|
||||
|
||||
|
|
@ -10,7 +10,7 @@ public class CiBuildSettings
|
|||
/// The global process environment variables
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
[JsonProperty("env")]
|
||||
[JsonPropertyName("env")]
|
||||
public string[] Environment { get; set; }
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -18,7 +18,7 @@ public class CiBuildSettings
|
|||
/// </summary>
|
||||
/// <value></value>
|
||||
[Required]
|
||||
[JsonPropertyAttribute("build")]
|
||||
[JsonPropertyName("build")]
|
||||
public CommandPipe Build { get; set; }
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -27,7 +27,7 @@ public class CiBuildSettings
|
|||
/// must end ok in order to launch the build.
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
[JsonPropertyAttribute("prepare")]
|
||||
[JsonPropertyName("prepare")]
|
||||
public CommandPipe Prepare { get; set; }
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -37,14 +37,14 @@ public class CiBuildSettings
|
|||
/// only fired on successful build.
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
[JsonPropertyAttribute("post_build")]
|
||||
[JsonPropertyName("post_build")]
|
||||
public CommandPipe PostBuild { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Additional emails, as dest of notifications
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
[JsonPropertyAttribute("emails")]
|
||||
[JsonPropertyName("emails")]
|
||||
public string[] Emails { get; set; }
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Diagnostics;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Yavsc.Abstract.IT
|
||||
{
|
||||
|
|
@ -13,17 +13,17 @@ namespace Yavsc.Abstract.IT
|
|||
public class Command
|
||||
{
|
||||
[Required]
|
||||
[JsonPropertyAttribute("path")]
|
||||
[JsonPropertyName("path")]
|
||||
public string Path { get; set; }
|
||||
|
||||
[JsonPropertyAttribute("args")]
|
||||
[JsonPropertyName("args")]
|
||||
public string[] Args { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Specific variables for this process
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
[JsonPropertyAttribute("env")]
|
||||
[JsonPropertyName("env")]
|
||||
public string[] Environment { get; set; }
|
||||
|
||||
public virtual Process Start(string workingDir=null, bool redirectInput=false, bool redirectOutput=false)
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
using System.Diagnostics;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Yavsc.Abstract.IT
|
||||
{
|
||||
|
|
@ -10,11 +8,11 @@ namespace Yavsc.Abstract.IT
|
|||
{
|
||||
|
||||
|
||||
[JsonPropertyAttribute("pipe")]
|
||||
[JsonPropertyName("pipe")]
|
||||
public Command[] Pipe { get; set; }
|
||||
|
||||
|
||||
[JsonPropertyAttribute("working_dir")]
|
||||
[JsonPropertyName("working_dir")]
|
||||
public string WorkingDir { get; set; }
|
||||
|
||||
public virtual int Run()
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ namespace Yavsc.Models.IT.Fixing
|
|||
ErrorMessageResourceName="TitleSizeError")]
|
||||
public string Title { get; set; }
|
||||
|
||||
[YaStringLength(10240,
|
||||
[StringLength(10240,
|
||||
ErrorMessageResourceType=typeof(Yavsc.Models.IT.Fixing.Bug),
|
||||
ErrorMessageResourceName="DescSizeError")]
|
||||
public string Description { get; set; }
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@ namespace Yavsc
|
|||
public interface ITrackedEntity
|
||||
{
|
||||
DateTime DateCreated { get; set; }
|
||||
string? UserCreated { get; set; }
|
||||
string UserCreated { get; set; }
|
||||
DateTime DateModified { get; set; }
|
||||
string? UserModified { get; set; }
|
||||
string UserModified { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net9.0</TargetFrameworks>
|
||||
<TargetFrameworks>net10.0</TargetFrameworks>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Description> A shared model for a little client/server app, dealing about establishing some contract, between some human client and provider.
|
||||
</Description>
|
||||
|
|
@ -8,8 +8,6 @@
|
|||
<RepositoryUrl>https://github.com/pazof/yavsc</RepositoryUrl>
|
||||
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
|
||||
<Library>true</Library>
|
||||
<LangVersion>latest</LangVersion>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ namespace cli.Commands
|
|||
});
|
||||
loginCommand.OnExecute(async () =>
|
||||
{
|
||||
string? authHostName = Program.AppConfiguration.GetRequiredSection("ConnectionSettings:ServerApi")["Authority"];
|
||||
string authHostName = Program.AppConfiguration.GetRequiredSection("ConnectionSettings:ServerApi")["Authority"];
|
||||
|
||||
throw new NotImplementedException();
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ using Microsoft.Extensions.Configuration;
|
|||
using Microsoft.Extensions.Hosting;
|
||||
internal class Program
|
||||
{
|
||||
public static IHost? AppHost { get; private set; }
|
||||
public static IHost AppHost { get; private set; }
|
||||
public static IConfigurationRoot AppConfiguration { get; private set; }
|
||||
public static IHostEnvironment AppEnvironment { get; private set; }
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@
|
|||
<PackageReference Include="Microsoft.Extensions.Configuration" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" />
|
||||
<PackageReference Include="Newtonsoft.Json" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Yavsc.Abstract\Yavsc.Abstract.csproj" />
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ public class PostItViewModelTests
|
|||
[Fact]
|
||||
public void SearchCommand_filters_posts_by_title_article_or_author()
|
||||
{
|
||||
var viewModel = new MainViewModel();
|
||||
var viewModel = new MainPageViewModel();
|
||||
|
||||
viewModel.Posts.Add(new BlogPost { Id = 1, Title = "First post", Article = "Hello world", AuthorId = "alice" });
|
||||
viewModel.Posts.Add(new BlogPost { Id = 2, Title = "Second post", Article = "Nothing here", AuthorId = "bob" });
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@
|
|||
<PackageReference Include="Microsoft.Extensions.Caching.Memory" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" />
|
||||
<PackageReference Include="Newtonsoft.Json" />
|
||||
<PackageReference Include="xunit" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" />
|
||||
</ItemGroup>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue