From c1f447636bf88a7ee2900616f5dae887d5e9ba19 Mon Sep 17 00:00:00 2001 From: Paul Schneider Date: Sat, 26 Sep 2026 18:02:53 +0100 Subject: [PATCH] [PostIT] #55 nearly ok, it-s better ... --- .vscode/settings.json | 6 +- src/PostIt/PostIt.Android/MainActivity.cs | 5 +- .../Helpers/ServiceCollectionHelpers.cs | 2 + src/PostIt/PostIt/ViewLocator.cs | 1 + .../ViewModels/Layout/AboutPageViewModel.cs | 77 +++++++++++++++++++ .../Layout/SessionStatusViewModel.cs | 7 ++ src/PostIt/PostIt/Views/Blogs/BlogsPage.axaml | 7 +- .../PostIt/Views/Blogs/BlogsPage.axaml.cs | 67 +++++++++++++++- .../PostIt/Views/Layout/AboutPage.axaml | 38 +++++++++ .../PostIt/Views/Layout/AboutPage.axaml.cs | 11 +++ .../Views/Layout/SessionStatusBanner.axaml | 3 + 11 files changed, 218 insertions(+), 6 deletions(-) create mode 100644 src/PostIt/PostIt/ViewModels/Layout/AboutPageViewModel.cs create mode 100644 src/PostIt/PostIt/Views/Layout/AboutPage.axaml create mode 100644 src/PostIt/PostIt/Views/Layout/AboutPage.axaml.cs diff --git a/.vscode/settings.json b/.vscode/settings.json index 7732a77b1..e6f2aee1d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -46,5 +46,9 @@ } }, "dotnet.defaultSolution": "yavsc.sln", - "axaml.selectedSolution": "/home/paul/Workspace/yavsc/yavsc.sln" + "axaml.selectedSolution": "/home/paul/Workspace/yavsc/yavsc.sln", + "chat.tools.terminal.autoApprove": { + "dotnet build": true, + "dotnet test": true + } } diff --git a/src/PostIt/PostIt.Android/MainActivity.cs b/src/PostIt/PostIt.Android/MainActivity.cs index 549100804..f8fd5a0fd 100644 --- a/src/PostIt/PostIt.Android/MainActivity.cs +++ b/src/PostIt/PostIt.Android/MainActivity.cs @@ -2,6 +2,7 @@ using Android.App; using Android.Content; using Android.Content.PM; +using Android.Views; using AndroidX.Core.Provider; using AndroidX.Emoji2.Text; using Avalonia.Android; @@ -15,7 +16,9 @@ namespace PostIt.Android; Theme = "@style/MyTheme.NoActionBar", Icon = "@drawable/icon", MainLauncher = true, - ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize | ConfigChanges.UiMode)] + WindowSoftInputMode = SoftInput.AdjustResize, + ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize | ConfigChanges.UiMode) + ] public class MainActivity : AvaloniaMainActivity { /// diff --git a/src/PostIt/PostIt/Helpers/ServiceCollectionHelpers.cs b/src/PostIt/PostIt/Helpers/ServiceCollectionHelpers.cs index 9616e7089..f6fcc3e3b 100644 --- a/src/PostIt/PostIt/Helpers/ServiceCollectionHelpers.cs +++ b/src/PostIt/PostIt/Helpers/ServiceCollectionHelpers.cs @@ -53,6 +53,7 @@ public static class ServiceCollectionHelpers // the navigation stack, each bound to a fresh // SettingsViewModel and missing any in-flight edits. services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); @@ -82,6 +83,7 @@ public static class ServiceCollectionHelpers services.AddSingleton(userFilesClient); services.AddSingleton(reverseGeocoding); services.AddSingleton(userDirectory); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); diff --git a/src/PostIt/PostIt/ViewLocator.cs b/src/PostIt/PostIt/ViewLocator.cs index 687a7cbd2..ae4662072 100644 --- a/src/PostIt/PostIt/ViewLocator.cs +++ b/src/PostIt/PostIt/ViewLocator.cs @@ -41,6 +41,7 @@ public class ViewLocator : IDataTemplate { BlogsViewModel => services.GetRequiredService(), Settings => services.GetRequiredService(), + AboutPageViewModel => services.GetRequiredService(), HomePageViewModel => services.GetRequiredService(), ActivitiesPageViewModel => services.GetRequiredService(), CommandFormsPageViewModel => services.GetRequiredService(), diff --git a/src/PostIt/PostIt/ViewModels/Layout/AboutPageViewModel.cs b/src/PostIt/PostIt/ViewModels/Layout/AboutPageViewModel.cs new file mode 100644 index 000000000..1082e4828 --- /dev/null +++ b/src/PostIt/PostIt/ViewModels/Layout/AboutPageViewModel.cs @@ -0,0 +1,77 @@ +using System; +using System.Reflection; +using System.Threading.Tasks; +using Avalonia.Controls; +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; + +namespace PostIt.ViewModels; + +/// +/// ViewModel de la page « À propos de PostIt ». Page statique : +/// version de l'application, description, licence et liens vers le +/// dépôt Forgejo et son suivi de tickets. +/// +public partial class AboutPageViewModel : ViewModelBase +{ + public const string RepositoryUrl = "https://forgejo.pschneider.fr/notazof/yavsc"; + public const string IssuesUrl = RepositoryUrl + "/issues"; + + public AboutPageViewModel() + { + Version = ReadVersion(); + } + + public string Version { get; } + + public string Description { get; } = + "PostIt est le client de la plateforme Yavsc : blog, devis, " + + "demandes de prestations et fichiers personnels."; + + public string License { get; } = + "Licence WTFPL — Do What The Fuck You Want To Public License, version 2"; + + public override bool CanNavigateNext + { + get => false; + protected set => throw new NotImplementedException(); + } + + public override bool CanNavigatePrevious + { + get => true; + protected set => throw new NotImplementedException(); + } + + [RelayCommand] + private Task OpenRepository() => OpenUrlAsync(RepositoryUrl); + + [RelayCommand] + private Task OpenIssues() => OpenUrlAsync(IssuesUrl); + + private static async Task OpenUrlAsync(string url) + { + var app = (App)App.Current!; + var topLevel = TopLevel.GetTopLevel(app.View); + if (topLevel is not null) + { + await topLevel.Launcher.LaunchUriAsync(new Uri(url)).ConfigureAwait(true); + } + } + + private static string ReadVersion() + { + var assembly = typeof(AboutPageViewModel).Assembly; + var info = assembly + .GetCustomAttribute() + ?.InformationalVersion; + if (!string.IsNullOrEmpty(info)) + { + // "1.1.0-estimate.1+364.Branch.x.Sha.y" → "1.1.0-estimate.1" + var plus = info.IndexOf('+'); + return plus > 0 ? info[..plus] : info; + } + + return assembly.GetName().Version?.ToString() ?? "inconnue"; + } +} diff --git a/src/PostIt/PostIt/ViewModels/Layout/SessionStatusViewModel.cs b/src/PostIt/PostIt/ViewModels/Layout/SessionStatusViewModel.cs index f2496b857..f55d1d9fb 100644 --- a/src/PostIt/PostIt/ViewModels/Layout/SessionStatusViewModel.cs +++ b/src/PostIt/PostIt/ViewModels/Layout/SessionStatusViewModel.cs @@ -143,4 +143,11 @@ public partial class SessionStatusViewModel : ViewModelBase await app.PushPageAsync(app.ServiceProvider!.GetRequiredService()).ConfigureAwait(true); } + [RelayCommand] + internal async Task OpenAbout() + { + var app = (App)App.Current!; + await app.PushPageAsync(app.ServiceProvider!.GetRequiredService()).ConfigureAwait(true); + } + } diff --git a/src/PostIt/PostIt/Views/Blogs/BlogsPage.axaml b/src/PostIt/PostIt/Views/Blogs/BlogsPage.axaml index 37c5bed64..65c01817d 100644 --- a/src/PostIt/PostIt/Views/Blogs/BlogsPage.axaml +++ b/src/PostIt/PostIt/Views/Blogs/BlogsPage.axaml @@ -175,6 +175,7 @@ PlaceholderText="Title" Text="{Binding DraftTitle, Mode=TwoWay}" /> + - 0) + { + double visibleHeight = this.Bounds.Height - keyboardHeight; + if (visibleHeight > 0) + { + MainContainer.Clip = new Avalonia.Media.RectangleGeometry( + new Avalonia.Rect(0, 0, this.Bounds.Width, visibleHeight)); + } + } + else + { + MainContainer.Clip = null; // Réinitialise le clip quand le clavier se ferme + } + */ + } + + private void OnInputPaneStateChanged(object? sender, InputPaneStateEventArgs e) + { + // e.EndRect contient le rectangle final du clavier virtuel + // e.EndRect.Height vous donne sa hauteur exacte en pixels indépendants du périphérique (pixels logiques) + UpdateLayoutForKeyboard(e.EndRect.Height); + } + protected override void OnApplyTemplate(TemplateAppliedEventArgs e) { base.OnApplyTemplate(e); diff --git a/src/PostIt/PostIt/Views/Layout/AboutPage.axaml b/src/PostIt/PostIt/Views/Layout/AboutPage.axaml new file mode 100644 index 000000000..5ad594e38 --- /dev/null +++ b/src/PostIt/PostIt/Views/Layout/AboutPage.axaml @@ -0,0 +1,38 @@ + + + + + + + + + +