[PostIT] #55 nearly ok, it-s better ...
Some checks failed
Dotnet build and test / build (pull_request) Failing after 33m44s
Some checks failed
Dotnet build and test / build (pull_request) Failing after 33m44s
This commit is contained in:
parent
94a9239cd5
commit
c1f447636b
11 changed files with 218 additions and 6 deletions
6
.vscode/settings.json
vendored
6
.vscode/settings.json
vendored
|
|
@ -46,5 +46,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dotnet.defaultSolution": "yavsc.sln",
|
"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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
using Android.App;
|
using Android.App;
|
||||||
using Android.Content;
|
using Android.Content;
|
||||||
using Android.Content.PM;
|
using Android.Content.PM;
|
||||||
|
using Android.Views;
|
||||||
using AndroidX.Core.Provider;
|
using AndroidX.Core.Provider;
|
||||||
using AndroidX.Emoji2.Text;
|
using AndroidX.Emoji2.Text;
|
||||||
using Avalonia.Android;
|
using Avalonia.Android;
|
||||||
|
|
@ -15,7 +16,9 @@ namespace PostIt.Android;
|
||||||
Theme = "@style/MyTheme.NoActionBar",
|
Theme = "@style/MyTheme.NoActionBar",
|
||||||
Icon = "@drawable/icon",
|
Icon = "@drawable/icon",
|
||||||
MainLauncher = true,
|
MainLauncher = true,
|
||||||
ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize | ConfigChanges.UiMode)]
|
WindowSoftInputMode = SoftInput.AdjustResize,
|
||||||
|
ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize | ConfigChanges.UiMode)
|
||||||
|
]
|
||||||
public class MainActivity : AvaloniaMainActivity
|
public class MainActivity : AvaloniaMainActivity
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,7 @@ public static class ServiceCollectionHelpers
|
||||||
// the navigation stack, each bound to a fresh
|
// the navigation stack, each bound to a fresh
|
||||||
// SettingsViewModel and missing any in-flight edits.
|
// SettingsViewModel and missing any in-flight edits.
|
||||||
services.AddSingleton<SettingsPage>();
|
services.AddSingleton<SettingsPage>();
|
||||||
|
services.AddSingleton<AboutPage>();
|
||||||
services.AddSingleton<HomePage>();
|
services.AddSingleton<HomePage>();
|
||||||
services.AddSingleton<SignaturePage>();
|
services.AddSingleton<SignaturePage>();
|
||||||
services.AddSingleton<CirclesPage>();
|
services.AddSingleton<CirclesPage>();
|
||||||
|
|
@ -82,6 +83,7 @@ public static class ServiceCollectionHelpers
|
||||||
services.AddSingleton(userFilesClient);
|
services.AddSingleton(userFilesClient);
|
||||||
services.AddSingleton<IReverseGeocodingService>(reverseGeocoding);
|
services.AddSingleton<IReverseGeocodingService>(reverseGeocoding);
|
||||||
services.AddSingleton<IUserDirectory>(userDirectory);
|
services.AddSingleton<IUserDirectory>(userDirectory);
|
||||||
|
services.AddSingleton<AboutPageViewModel>();
|
||||||
services.AddSingleton<HomePageViewModel>();
|
services.AddSingleton<HomePageViewModel>();
|
||||||
services.AddSingleton<SignaturePageViewModel>();
|
services.AddSingleton<SignaturePageViewModel>();
|
||||||
services.AddSingleton<CirclesPageViewModel>();
|
services.AddSingleton<CirclesPageViewModel>();
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@ public class ViewLocator : IDataTemplate
|
||||||
{
|
{
|
||||||
BlogsViewModel => services.GetRequiredService<BlogsPage>(),
|
BlogsViewModel => services.GetRequiredService<BlogsPage>(),
|
||||||
Settings => services.GetRequiredService<SettingsPage>(),
|
Settings => services.GetRequiredService<SettingsPage>(),
|
||||||
|
AboutPageViewModel => services.GetRequiredService<AboutPage>(),
|
||||||
HomePageViewModel => services.GetRequiredService<HomePage>(),
|
HomePageViewModel => services.GetRequiredService<HomePage>(),
|
||||||
ActivitiesPageViewModel => services.GetRequiredService<ActivitiesPage>(),
|
ActivitiesPageViewModel => services.GetRequiredService<ActivitiesPage>(),
|
||||||
CommandFormsPageViewModel => services.GetRequiredService<CommandFormsPage>(),
|
CommandFormsPageViewModel => services.GetRequiredService<CommandFormsPage>(),
|
||||||
|
|
|
||||||
77
src/PostIt/PostIt/ViewModels/Layout/AboutPageViewModel.cs
Normal file
77
src/PostIt/PostIt/ViewModels/Layout/AboutPageViewModel.cs
Normal file
|
|
@ -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;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
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<AssemblyInformationalVersionAttribute>()
|
||||||
|
?.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";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -143,4 +143,11 @@ public partial class SessionStatusViewModel : ViewModelBase
|
||||||
await app.PushPageAsync(app.ServiceProvider!.GetRequiredService<Settings>()).ConfigureAwait(true);
|
await app.PushPageAsync(app.ServiceProvider!.GetRequiredService<Settings>()).ConfigureAwait(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
internal async Task OpenAbout()
|
||||||
|
{
|
||||||
|
var app = (App)App.Current!;
|
||||||
|
await app.PushPageAsync(app.ServiceProvider!.GetRequiredService<AboutPageViewModel>()).ConfigureAwait(true);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -175,6 +175,7 @@
|
||||||
PlaceholderText="Title"
|
PlaceholderText="Title"
|
||||||
Text="{Binding DraftTitle, Mode=TwoWay}" />
|
Text="{Binding DraftTitle, Mode=TwoWay}" />
|
||||||
|
|
||||||
|
|
||||||
<AvaloniaEdit:TextEditor
|
<AvaloniaEdit:TextEditor
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
VerticalAlignment="Stretch"
|
VerticalAlignment="Stretch"
|
||||||
|
|
@ -186,10 +187,12 @@
|
||||||
BorderBrush="LightGray"
|
BorderBrush="LightGray"
|
||||||
CornerRadius="5"
|
CornerRadius="5"
|
||||||
Padding="5,5,5,15"
|
Padding="5,5,5,15"
|
||||||
|
HorizontalScrollBarVisibility="Disabled"
|
||||||
|
TextInputOptions.Multiline="True"
|
||||||
|
TextInputOptions.ReturnKeyType="Default"
|
||||||
|
ClipToBounds="True"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
||||||
<Border
|
<Border
|
||||||
Grid.Row="3"
|
Grid.Row="3"
|
||||||
Padding="8"
|
Padding="8"
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,82 @@
|
||||||
using System;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Platform.Storage;
|
using Avalonia.Platform.Storage;
|
||||||
using Avalonia.Controls.Primitives;
|
using Avalonia.Controls.Primitives;
|
||||||
|
using Avalonia.Interactivity;
|
||||||
|
using Avalonia.Controls.Platform;
|
||||||
|
|
||||||
namespace PostIt.Views.Blogs;
|
namespace PostIt.Views.Blogs;
|
||||||
|
|
||||||
public partial class BlogsPage : ContentPage
|
public partial class BlogsPage : ContentPage
|
||||||
{
|
{
|
||||||
|
private IInputPane _inputPane;
|
||||||
|
|
||||||
public BlogsPage()
|
public BlogsPage()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void OnLoaded(RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
base.OnLoaded(e);
|
||||||
|
|
||||||
|
// Récupère l'accès au TopLevel de la fenêtre/application
|
||||||
|
var topLevel = TopLevel.GetTopLevel(this);
|
||||||
|
if (topLevel != null)
|
||||||
|
{
|
||||||
|
_inputPane = topLevel.InputPane;
|
||||||
|
if (_inputPane != null)
|
||||||
|
{
|
||||||
|
// S'abonne aux changements d'état du clavier virtuel
|
||||||
|
_inputPane.StateChanged += OnInputPaneStateChanged;
|
||||||
|
|
||||||
|
// Applique la configuration initiale si le clavier est déjà présent
|
||||||
|
UpdateLayoutForKeyboard(_inputPane.OccludedRect.Height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnUnloaded(RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (_inputPane != null)
|
||||||
|
{
|
||||||
|
_inputPane.StateChanged -= OnInputPaneStateChanged;
|
||||||
|
}
|
||||||
|
base.OnUnloaded(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void UpdateLayoutForKeyboard(double keyboardHeight)
|
||||||
|
{
|
||||||
|
var app = App.Current as App;
|
||||||
|
|
||||||
|
app.View.Margin = new Avalonia.Thickness(0, 0, 0, keyboardHeight);
|
||||||
|
// OPTION B : Si vous devez explicitement appliquer un masque de découpage (Clip) basé sur la hauteur :
|
||||||
|
/*
|
||||||
|
if (keyboardHeight > 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)
|
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
||||||
{
|
{
|
||||||
base.OnApplyTemplate(e);
|
base.OnApplyTemplate(e);
|
||||||
|
|
|
||||||
38
src/PostIt/PostIt/Views/Layout/AboutPage.axaml
Normal file
38
src/PostIt/PostIt/Views/Layout/AboutPage.axaml
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
<ContentPage xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:vm="using:PostIt.ViewModels"
|
||||||
|
x:Class="PostIt.Views.AboutPage"
|
||||||
|
x:DataType="vm:AboutPageViewModel"
|
||||||
|
Header="À propos">
|
||||||
|
<Design.DataContext>
|
||||||
|
<vm:AboutPageViewModel />
|
||||||
|
</Design.DataContext>
|
||||||
|
<StackPanel HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Spacing="12"
|
||||||
|
Margin="16">
|
||||||
|
<TextBlock Text="PostIt"
|
||||||
|
FontSize="28"
|
||||||
|
FontWeight="Bold"
|
||||||
|
HorizontalAlignment="Center"/>
|
||||||
|
<TextBlock Text="{Binding Version, StringFormat='Version {0}'}"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
Opacity="0.8"/>
|
||||||
|
<TextBlock Text="{Binding Description}"
|
||||||
|
TextWrapping="Wrap"
|
||||||
|
TextAlignment="Center"
|
||||||
|
MaxWidth="420"/>
|
||||||
|
<TextBlock Text="{Binding License}"
|
||||||
|
TextWrapping="Wrap"
|
||||||
|
TextAlignment="Center"
|
||||||
|
MaxWidth="420"
|
||||||
|
Opacity="0.8"
|
||||||
|
FontStyle="Italic"/>
|
||||||
|
<Button Content="Dépôt du projet"
|
||||||
|
Command="{Binding OpenRepositoryCommand}"
|
||||||
|
HorizontalAlignment="Center"/>
|
||||||
|
<Button Content="Signaler un problème"
|
||||||
|
Command="{Binding OpenIssuesCommand}"
|
||||||
|
HorizontalAlignment="Center"/>
|
||||||
|
</StackPanel>
|
||||||
|
</ContentPage>
|
||||||
11
src/PostIt/PostIt/Views/Layout/AboutPage.axaml.cs
Normal file
11
src/PostIt/PostIt/Views/Layout/AboutPage.axaml.cs
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
using Avalonia.Controls;
|
||||||
|
|
||||||
|
namespace PostIt.Views;
|
||||||
|
|
||||||
|
public partial class AboutPage : ContentPage
|
||||||
|
{
|
||||||
|
public AboutPage()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -28,6 +28,9 @@
|
||||||
<Button Content="Paramètres"
|
<Button Content="Paramètres"
|
||||||
Command="{Binding OpenSettingsCommand}"
|
Command="{Binding OpenSettingsCommand}"
|
||||||
DockPanel.Dock="Right"/>
|
DockPanel.Dock="Right"/>
|
||||||
|
<Button Content="À propos"
|
||||||
|
Command="{Binding OpenAboutCommand}"
|
||||||
|
DockPanel.Dock="Right"/>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</Border>
|
</Border>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue