diff --git a/Directory.Packages.props b/Directory.Packages.props index 19d2fdf8..9f3701fc 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -10,6 +10,7 @@ + @@ -24,7 +25,6 @@ - @@ -34,10 +34,8 @@ - - @@ -46,12 +44,9 @@ - - - @@ -60,16 +55,14 @@ - - - + @@ -81,6 +74,5 @@ - - + \ No newline at end of file diff --git a/src/PostIt/PostIt/App.axaml.cs b/src/PostIt/PostIt/App.axaml.cs index 6919f09d..66592224 100644 --- a/src/PostIt/PostIt/App.axaml.cs +++ b/src/PostIt/PostIt/App.axaml.cs @@ -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() }; } diff --git a/src/PostIt/PostIt/Settings/Settings.cs b/src/PostIt/PostIt/Settings/Settings.cs index 462faedd..1064004c 100644 --- a/src/PostIt/PostIt/Settings/Settings.cs +++ b/src/PostIt/PostIt/Settings/Settings.cs @@ -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,41 +40,44 @@ 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(); - - using var reader = new StreamReader( stream); - var json = await reader.ReadToEndAsync(); - if (string.IsNullOrWhiteSpace(json)) - { - Console.Error.WriteLine("🩎 Settings file is empty."); - return ; - } + Console.WriteLine($"🔎 Loading settings from {configFileInfo.FullName}"); - var settings = JsonSerializer.Deserialize(json); + try + { + using var stream = configFileInfo.OpenRead(); + using var reader = new StreamReader(stream); + var json = await reader.ReadToEndAsync(); + if (string.IsNullOrWhiteSpace(json)) + { + Console.Error.WriteLine("🩎 Settings file is empty."); + return; + } - if (settings is null) - { - Console.Error.WriteLine("🩎 Settings file is invalid."); - return ; - } - this.Authentication = settings.Authentication; - this.DarkMode = settings.DarkMode; - this.ApiUrl = settings.ApiUrl; - this.Scopes = settings.Scopes; + var settings = JsonSerializer.Deserialize(json); + + if (settings is null) + { + Console.Error.WriteLine("🩎 Settings file is invalid."); + return; + } + this.Authentication = settings.Authentication; + this.DarkMode = settings.DarkMode; + this.ApiUrl = settings.ApiUrl; + this.Scopes = settings.Scopes; - } catch (Exception ex) { diff --git a/src/PostIt/PostIt/ViewLocator.cs b/src/PostIt/PostIt/ViewLocator.cs index 7c03656f..38f2b3fe 100644 --- a/src/PostIt/PostIt/ViewLocator.cs +++ b/src/PostIt/PostIt/ViewLocator.cs @@ -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; /// /// Given a view model, returns the corresponding view if possible. /// -[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 data switch { - return (Control)Activator.CreateInstance(type)!; - } - - return new TextBlock { Text = "Not Found: " + name }; + MainPageViewModel => _services.GetRequiredService(), + SettingsPageViewModel => _services.GetRequiredService(), + _ => new TextBlock { Text = $"No view for {data.GetType().Name}" } + }; } - public bool Match(object? data) - { - return data is ViewModelBase; - } + public bool Match(object data) => data is ViewModelBase; } \ No newline at end of file diff --git a/src/PostIt/PostIt/ViewModels/HomePageViewModel.cs b/src/PostIt/PostIt/ViewModels/HomePageViewModel.cs new file mode 100644 index 00000000..d56711af --- /dev/null +++ b/src/PostIt/PostIt/ViewModels/HomePageViewModel.cs @@ -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(); } + +} \ No newline at end of file diff --git a/src/PostIt/PostIt/ViewModels/MainViewModel.cs b/src/PostIt/PostIt/ViewModels/MainViewModel.cs index 6dcc951d..10f9febe 100644 --- a/src/PostIt/PostIt/ViewModels/MainViewModel.cs +++ b/src/PostIt/PostIt/ViewModels/MainViewModel.cs @@ -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; } @@ -34,18 +40,20 @@ public partial class MainViewModel : ViewModelBase public partial ObservableCollection FilteredPosts { get; set; } [ObservableProperty] - public partial BlogPost? SelectedPost{ get; set; } + public partial BlogPost? SelectedPost { get; set; } [ObservableProperty] - public partial bool IsBusy{ get; set; } + public partial bool IsBusy { get; set; } [ObservableProperty] ThemeVariant themeVariant = ThemeVariant.Default; - + [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(); @@ -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() { @@ -224,7 +241,7 @@ public partial class MainViewModel : ViewModelBase private void ApplyFilter() { if (Posts is null) return; - + var query = SearchText?.Trim(); var filtered = string.IsNullOrWhiteSpace(query) ? Posts.OrderByDescending(p => p.DateModified) @@ -299,6 +316,7 @@ public partial class MainViewModel : ViewModelBase return payload; } + private static readonly JsonSerializerOptions JsonOptions = new() { PropertyNameCaseInsensitive = true diff --git a/src/PostIt/PostIt/ViewModels/SettingsViewModel.cs b/src/PostIt/PostIt/ViewModels/SettingsViewModel.cs index aab3b2af..2f871ee1 100644 --- a/src/PostIt/PostIt/ViewModels/SettingsViewModel.cs +++ b/src/PostIt/PostIt/ViewModels/SettingsViewModel.cs @@ -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(); } } diff --git a/src/PostIt/PostIt/ViewModels/ViewModelBase.cs b/src/PostIt/PostIt/ViewModels/ViewModelBase.cs index 3d28c6dd..93019360 100644 --- a/src/PostIt/PostIt/ViewModels/ViewModelBase.cs +++ b/src/PostIt/PostIt/ViewModels/ViewModelBase.cs @@ -5,4 +5,15 @@ namespace PostIt.ViewModels; public abstract partial class ViewModelBase : ObservableObject { + + /// + /// Gets if the user can navigate to the next page + /// + public abstract bool CanNavigateNext { get; protected set; } + + /// + /// Gets if the user can navigate to the previous page + /// + public abstract bool CanNavigatePrevious { get; protected set; } + } diff --git a/src/PostIt/PostIt/Views/HomePage.axaml b/src/PostIt/PostIt/Views/HomePage.axaml new file mode 100644 index 00000000..1c188b31 --- /dev/null +++ b/src/PostIt/PostIt/Views/HomePage.axaml @@ -0,0 +1,16 @@ + + + +