From beeac586284dfca3a10df7a283d79a047ff39b43 Mon Sep 17 00:00:00 2001 From: Paul Schneider Date: Tue, 25 Aug 2026 14:16:49 +0100 Subject: [PATCH] test are still ok! --- .vscode/launch.json | 2 +- .vscode/tasks.json | 70 +++++-------------- Directory.Build.props | 2 +- src/PostIt/Directory.Packages.props | 36 +++++----- src/PostIt/Makefile | 7 ++ src/PostIt/PostIt.Android/MainActivity.cs | 23 ++++-- .../PostIt.Android/PostIt.Android.csproj | 12 ++-- .../Resources/values/font_certs.xml | 13 ++++ .../AddCircleMemberDialogTests.cs | 5 +- .../PostIt.Tests/AndroidAppLaunchTests.cs | 2 +- .../PostIt.Tests/MainPageButtonsTests.cs | 11 ++- src/PostIt/PostIt.Tests/PostAclDialogTests.cs | 5 +- .../PostIt.Tests/SessionStatusBannerTests.cs | 17 ++--- src/PostIt/PostIt.Tests/TestAppContext.cs | 2 +- src/PostIt/PostIt.Tests/UnitTest1.cs | 3 +- src/PostIt/PostIt/App.axaml | 1 - src/PostIt/PostIt/App.axaml.cs | 62 ++++++++-------- .../Helpers/ServiceCollectionHelpers.cs | 7 +- .../PostIt/Helpers/ViewModelBaseHelpers.cs | 2 +- src/PostIt/PostIt/PostIt.csproj | 1 - .../PostIt/Services/ContactService.Desktop.cs | 36 ---------- src/PostIt/PostIt/Views/MainPage.axaml | 14 +--- src/PostIt/PostIt/Views/MainView.axaml | 22 ++++++ src/PostIt/PostIt/Views/MainView.axaml.cs | 11 +++ src/PostIt/PostIt/Views/MainWindow.axaml | 9 +-- src/PostIt/PostIt/Views/MainWindow.axaml.cs | 2 +- src/PostIt/PostIt/Views/TextEditorBinding.cs | 51 -------------- 27 files changed, 170 insertions(+), 258 deletions(-) create mode 100644 src/PostIt/Makefile create mode 100644 src/PostIt/PostIt.Android/Resources/values/font_certs.xml delete mode 100644 src/PostIt/PostIt/Services/ContactService.Desktop.cs create mode 100644 src/PostIt/PostIt/Views/MainView.axaml create mode 100644 src/PostIt/PostIt/Views/MainView.axaml.cs delete mode 100644 src/PostIt/PostIt/Views/TextEditorBinding.cs diff --git a/.vscode/launch.json b/.vscode/launch.json index 7ea523c9..36dc17a2 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,7 +5,7 @@ "version": "0.2.0", "configurations": [ { - "name": "Debug - Android", + "name": "Android", "type": "mono", "preLaunchTask": "run-debug-android", "request": "attach", diff --git a/.vscode/tasks.json b/.vscode/tasks.json index a80c4741..9fe9caaf 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -15,12 +15,27 @@ }, "args": [ "run", + "-p:TargetFramework=net10.0-android", "-p:Configuration=Debug", "-p:AndroidAttachDebugger=true", "-p:AndroidSdbHostPort=10000", "-p:AndroidSdbTargetPort=10000" ], - "problemMatcher": "$msCompile" + "problemMatcher": [ + { + "owner": "dotnet", + "fileLocation": ["relative", "${workspaceFolder}"], + "source": "dotnet", + "pattern": { + "regexp": "^(.*):(\\d+):(\\d+):\\s+(error):\\s+(.*)$", + "file": 1, + "line": 2, + "column": 3, + "severity": 4, + "message": 5 + } + } + ] }, { "label": "build", @@ -60,59 +75,6 @@ "kind": "build" }, "isBackground": true - }, - { - "label": "test blogs", - "type": "process", - "problemMatcher": ["$msCompile"], - "command": "dotnet", - "args": ["test"], - "runOptions": { - "instanceLimit": 1 - }, - "options": { - "cwd": "src/Yavsc.Blogs", - "env": { - "DOTNET_CLI_UI_LANGUAGE": "en-US", - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, - "group": { - "kind": "test" - }, - "isBackground": true, - "presentation": { - "echo": true, - "reveal": "always", - "focus": false, - "panel": "shared", - "showReuseMessage": true, - "clear": false - } - }, - { - "label": "publish", - "command": "dotnet", - "type": "process", - "args": [ - "publish", - "/property:GenerateFullPaths=true", - "/consoleloggerparameters:NoSummary;ForceNoAlign" - ], - "problemMatcher": "$msCompile" - }, - { - "label": "watch", - "command": "dotnet", - "type": "process", - "args": ["watch", "--project", - "src/Yavsc.Org/Yavsc.Org.csproj" - ], - "problemMatcher": "$msCompile", - "runOptions": { - - } - } ] } diff --git a/Directory.Build.props b/Directory.Build.props index aec8c990..0ce825bd 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -11,6 +11,6 @@ from without conflicting names. --> true - NU1701, NU1901, NU1902 + NU1701, NU1901, NU1902, NU1507 diff --git a/src/PostIt/Directory.Packages.props b/src/PostIt/Directory.Packages.props index 69e8a896..0d5fa50c 100644 --- a/src/PostIt/Directory.Packages.props +++ b/src/PostIt/Directory.Packages.props @@ -5,33 +5,35 @@ true + 12.1.1 - - - - - - - - - + + + + + + + + + - + - - - - - - - + + + + + + + + diff --git a/src/PostIt/Makefile b/src/PostIt/Makefile new file mode 100644 index 00000000..72158bfa --- /dev/null +++ b/src/PostIt/Makefile @@ -0,0 +1,7 @@ + +clean: clean-PostIt clean-PostIt.Android clean-PostIt.Desktop + +clean-%: + rm -rf $*/obj $*/bin + +.PHONY: clean diff --git a/src/PostIt/PostIt.Android/MainActivity.cs b/src/PostIt/PostIt.Android/MainActivity.cs index 62c29e10..4f788550 100644 --- a/src/PostIt/PostIt.Android/MainActivity.cs +++ b/src/PostIt/PostIt.Android/MainActivity.cs @@ -1,8 +1,13 @@ -using Android.App; +using Android; +using Android.App; using Android.Content; using Android.Content.PM; +using AndroidX.Core.Provider; +using AndroidX.Emoji2.Text; using Avalonia; using Avalonia.Android; +using AndroidX.Core.Provider; +using AndroidX.Emoji2.Text; namespace PostIt.Android; @@ -15,18 +20,22 @@ namespace PostIt.Android; ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize | ConfigChanges.UiMode)] public class MainActivity : AvaloniaMainActivity { - /// - /// Strongly-typed handle to the current MainActivity instance, set in - /// and consumed by platform services such as - /// which need to launch - /// Chrome Custom Tabs. + /// + /// The current MainActivity instance. /// public static MainActivity? Current { get; private set; } protected override void OnCreate(global::Android.OS.Bundle? savedInstanceState) { - base.OnCreate(savedInstanceState); + FontRequest fontRequest = new FontRequest( + "com.google.android.gms.fonts", + "com.google.android.gms", + "Noto Color Emoji Compat", + Yavsc.Resource.Array.com_google_android_gms_fonts_certs); //com_google_android_gms_fonts_certs + EmojiCompat.Config config = new FontRequestEmojiCompatConfig(this, fontRequest); + EmojiCompat.Init(config); PlatformBootstrap.EnsureInitialized(); + base.OnCreate(savedInstanceState); Current = this; } /// diff --git a/src/PostIt/PostIt.Android/PostIt.Android.csproj b/src/PostIt/PostIt.Android/PostIt.Android.csproj index a4af1eb2..62b494f8 100644 --- a/src/PostIt/PostIt.Android/PostIt.Android.csproj +++ b/src/PostIt/PostIt.Android/PostIt.Android.csproj @@ -4,13 +4,11 @@ net10.0-android 23 enable - fr.pschneider.PostIt + fr.pschneider.postit 1 1.0 apk - false - SdkOnly - partial + false @@ -23,11 +21,11 @@ - - - + + + diff --git a/src/PostIt/PostIt.Android/Resources/values/font_certs.xml b/src/PostIt/PostIt.Android/Resources/values/font_certs.xml new file mode 100644 index 00000000..f4adce1b --- /dev/null +++ b/src/PostIt/PostIt.Android/Resources/values/font_certs.xml @@ -0,0 +1,13 @@ + + + + @array/com_google_android_gms_fonts_certs_dev + @array/com_google_android_gms_fonts_certs_prod + + + MIIEqDCCA5CgAwIBAgIJAN5gc16AJfAsMA0GCSqGSIb3DQEBBQUAMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHR29vZ2xlMRAwDgYDVQQLEwdBbmRyb2lkMRAwDgYDVQQDEwdBbmRyb2lkMSEwHwYJKoZIhvcNAQkBFhJhbmRyb2lkQGFuZHJvaWQuY29tMCAXDTA4MDQxNTIyNDA0M1YYDzQyMDgxMzA0MjI0MDQzWjCBlDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDURvdW50YWluIFZpZXcxEDAOBgNVBAoTB0dvb2dsZTEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEhMB8GCSqGSIb3DQEJARYSYW5kcm9pZEBhbmRyb2lkLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALBi1vF0K1vOEHG7AxneTjOHUka46MIidBqvFcO164A49iU2DkYPhUaM4H8JCdzh6N1GzM6h9o6E2V6z8+gEtdI6nqqs0EGA0G0H701bFjLp9+K/1DkMIFeD4P8J7X1/M8t4+X09X/7bQyV3w0v7q+Qh38sY8W/7K29B3f2O2sLw+uX9U8a8Tf4Xv8A== + + + MIIEQzCCAyugAwIBAgIJAMLgh0ZgXpYOMA0GCSqGSIb3DQEBBQUAMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDAeFw0wODA4MjEyMzEzMzRaFw0zNjAxMDcyMzEzMzRaMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKKvSkUIXm+t9M8rXj2V + + diff --git a/src/PostIt/PostIt.Tests/AddCircleMemberDialogTests.cs b/src/PostIt/PostIt.Tests/AddCircleMemberDialogTests.cs index 91413ca0..8bec1dc6 100644 --- a/src/PostIt/PostIt.Tests/AddCircleMemberDialogTests.cs +++ b/src/PostIt/PostIt.Tests/AddCircleMemberDialogTests.cs @@ -73,7 +73,7 @@ public class AddCircleMemberDialogTests return context; } /// - /// Mount a real , build a minimal + /// Mount a real , build a minimal /// DI graph, push then the /// on top of it. /// Returns the stack size so the test can pin the delta. @@ -98,10 +98,9 @@ public class AddCircleMemberDialogTests services.AddTransient(); var sp = services.BuildServiceProvider(); - context.Window = new MainWindow(); + context.Window = new MainView(); context.App = (PostIt.App)Application.Current!; context.App.AttachMainWindow(context.Window); - context.Window.Show(); context.page = sp.GetRequiredService(); context.Window.NavRoot.PushAsync(context.page).GetAwaiter().GetResult(); diff --git a/src/PostIt/PostIt.Tests/AndroidAppLaunchTests.cs b/src/PostIt/PostIt.Tests/AndroidAppLaunchTests.cs index ac4756eb..23b423e1 100644 --- a/src/PostIt/PostIt.Tests/AndroidAppLaunchTests.cs +++ b/src/PostIt/PostIt.Tests/AndroidAppLaunchTests.cs @@ -23,7 +23,7 @@ public class AndroidAppLaunchTests _output = output; } - // FIXME [Fact] + [Fact] public void PostIt_starts_and_draws_a_first_frame_on_the_emulator() { if (!IsPackageInstalledOnAnyDevice()) diff --git a/src/PostIt/PostIt.Tests/MainPageButtonsTests.cs b/src/PostIt/PostIt.Tests/MainPageButtonsTests.cs index cd3684ef..d1d00532 100644 --- a/src/PostIt/PostIt.Tests/MainPageButtonsTests.cs +++ b/src/PostIt/PostIt.Tests/MainPageButtonsTests.cs @@ -99,7 +99,7 @@ public class MainPageButtonsTests } /// - /// Mount a real (as + /// Mount a real (as /// SessionStatusBannerTests does), push a /// with the given VM onto /// NavRoot. PushAsync is awaited (via @@ -109,13 +109,12 @@ public class MainPageButtonsTests /// realised and KeyPressQwerty has a real /// to dispatch against. /// - private static (MainWindow window, MainPage page) MountMainPage(MainViewModel vm) + private static (MainView window, MainPage page) MountMainPage(MainViewModel vm) { - var window = new MainWindow(); + var window = new MainView(); var page = new MainPage { DataContext = vm }; var app = (PostIt.App)Application.Current!; app.AttachMainWindow(window); - window.Show(); window.NavRoot.PushAsync(page).GetAwaiter().GetResult(); return (window, page); } @@ -125,7 +124,7 @@ public class MainPageButtonsTests /// supported headless pattern (cf. CalculatorTests in the /// Avalonia.Samples repo). Returns the nav-stack count /// before the click so the caller can assert on the delta. - /// KeyPressQwerty is dispatched on the + /// KeyPressQwerty is dispatched on the /// itself — it is the that owns the /// headless implementation, and routing the key through any /// descendant TopLevel (e.g. one obtained via @@ -134,7 +133,7 @@ public class MainPageButtonsTests /// because the descendant does not carry the /// PlatformHandle the harness expects. /// - private static int ClickAndCapture(MainWindow window, Button button) + private static int ClickAndCapture(MainView window, Button button) { var stackBefore = window.NavRoot.NavigationStack.Count; button.Command?.Execute(button.CommandParameter); diff --git a/src/PostIt/PostIt.Tests/PostAclDialogTests.cs b/src/PostIt/PostIt.Tests/PostAclDialogTests.cs index d13468f0..ccb33ec7 100644 --- a/src/PostIt/PostIt.Tests/PostAclDialogTests.cs +++ b/src/PostIt/PostIt.Tests/PostAclDialogTests.cs @@ -117,7 +117,7 @@ public class PostAclDialogTests /// rebinding the global DI mid-test would trample the /// Settings singleton the rest of the harness depends on. /// - private static (MainWindow window, BlogAclApiClient aclClient, CircleApiClient circleClient, CountingHttpHandler handler) Mount() + private static (MainView window, BlogAclApiClient aclClient, CircleApiClient circleClient, CountingHttpHandler handler) Mount() { var handler = new CountingHttpHandler(); var settings = new Settings(); @@ -138,10 +138,9 @@ public class PostAclDialogTests // CountingHttpHandler. GC.KeepAlive(sp); - var window = new MainWindow(); + var window = new MainView(); var app = (App)Application.Current!; app.AttachMainWindow(window); - window.Show(); return (window, aclClient, circleClient, handler); } diff --git a/src/PostIt/PostIt.Tests/SessionStatusBannerTests.cs b/src/PostIt/PostIt.Tests/SessionStatusBannerTests.cs index e1a5dd19..0a28ee87 100644 --- a/src/PostIt/PostIt.Tests/SessionStatusBannerTests.cs +++ b/src/PostIt/PostIt.Tests/SessionStatusBannerTests.cs @@ -9,7 +9,7 @@ namespace PostIt.Tests; /// /// UI tests for . Mounted inside -/// a real via the headless Avalonia +/// a real via the headless Avalonia /// platform declared in TestApp.cs. /// /// The pattern is the one that UnitTest1.MainPage_Should_Load @@ -34,9 +34,8 @@ public class SessionStatusBannerTests [AvaloniaFact] public void Banner_renders_three_buttons_in_the_visual_tree() { - var window = new MainWindow(); + var window = new MainView(); window.SessionBanner.DataContext = new SessionStatusViewModel(); - window.Show(); var buttons = window.SessionBanner.GetVisualDescendants() .OfType public IServiceProvider? ServiceProvider { get; private set; } - public MainWindow? Window { get; private set; } + public MainView? View { get; private set; } public override void Initialize() { @@ -44,10 +44,28 @@ public partial class App : Application this.ServiceProvider = new ServiceCollection().BuildServices(); var settings = ServiceProvider.GetRequiredService(); + var sessionStatus = ServiceProvider!.GetRequiredService(); + sessionStatus.LogoutCompleted += () => + { + View.NavRoot.PopToRootAsync(); + }; + sessionStatus.LoginSucceeded += () => + { + PushMainPageAsync(); + }; if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { - desktop.MainWindow = Window = CreateMainWindow(); + var window = ServiceProvider.GetRequiredService(); + desktop.MainWindow = window; + var api = ServiceProvider!.GetRequiredService(); + desktop.MainWindow.Opened += async (_, _) => await BootAsync(this.ServiceProvider!, api); + + View = window.MainView; + + View.SessionBanner.DataContext = sessionStatus; + // FIXME Window.Opened += async (_, _) => await BootAsync(this.ServiceProvider!, api); + ApplyDarkMode(settings); } else if (ApplicationLifetime is IActivityApplicationLifetime singleViewFactoryApplicationLifetime) @@ -55,54 +73,34 @@ public partial class App : Application singleViewFactoryApplicationLifetime.MainViewFactory = () => { - Window = CreateMainWindow(); + View = ServiceProvider.GetRequiredService(); ApplyDarkMode(settings); - Window.Show(); - return Window; + View.SessionBanner.DataContext = sessionStatus; + return View; }; } else if (ApplicationLifetime is ISingleViewApplicationLifetime singleViewPlatform) { - singleViewPlatform.MainView = Window = CreateMainWindow(); + singleViewPlatform.MainView = View = ServiceProvider.GetRequiredService(); + View.SessionBanner.DataContext = sessionStatus; ApplyDarkMode(settings); } var mainVm = ServiceProvider!.GetRequiredService(); base.OnFrameworkInitializationCompleted(); - this.PushPageAsync(mainVm).Wait(); + this.PushPageAsync(mainVm); } - - private MainWindow CreateMainWindow() - { - Window = new MainWindow(); - var api = ServiceProvider!.GetRequiredService(); - Window.Opened += async (_, _) => await BootAsync(this.ServiceProvider!, api); - var sessionStatus = ServiceProvider!.GetRequiredService(); - sessionStatus.LogoutCompleted += () => - { - Window.NavRoot.PopToRootAsync(); - }; - - sessionStatus.LoginSucceeded += () => - { - PushMainPageAsync(); - }; - - Window.SessionBanner.DataContext = sessionStatus; - return Window; - } - /// - /// Test-only hook: bind a concrete so + /// Test-only hook: bind a concrete so /// command-driven navigation paths () can /// push onto a real in headless /// fixtures that do not run the full desktop lifetime bootstrap. /// - internal void AttachMainWindow(MainWindow mainWindow) + internal void AttachMainWindow(MainView mainWindow) { - Window = mainWindow ?? throw new ArgumentNullException(nameof(mainWindow)); + View = mainWindow ?? throw new ArgumentNullException(nameof(mainWindow)); } private static void ApplyDarkMode(Settings settings) @@ -180,6 +178,6 @@ public partial class App : Application internal async Task GoBackAsync() { - await Window!.NavRoot.PopAsync(); + await View!.NavRoot.PopAsync(); } } diff --git a/src/PostIt/PostIt/Helpers/ServiceCollectionHelpers.cs b/src/PostIt/PostIt/Helpers/ServiceCollectionHelpers.cs index fae24fa6..c4e774cc 100644 --- a/src/PostIt/PostIt/Helpers/ServiceCollectionHelpers.cs +++ b/src/PostIt/PostIt/Helpers/ServiceCollectionHelpers.cs @@ -23,11 +23,13 @@ public static class ServiceCollectionHelpers var circleClient = new CircleApiClient(api, settings.BlogsApiUrl); var blogAclClient = new BlogAclApiClient(api, settings.BlogsApiUrl); var userSearchClient = new UserSearchClient(api, settings.BlogsApiUrl); - var contactService = new ContactService(); var userDirectory = new UserDirectory(userSearchClient); // Vues - services.AddTransient(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + // SettingsPage is a singleton: there must be one and only one // instance of the settings UI for the lifetime of the app. // This guarantees that (a) the bindings always reflect the @@ -58,7 +60,6 @@ public static class ServiceCollectionHelpers services.AddSingleton(circleClient); services.AddSingleton(blogAclClient); services.AddSingleton(userSearchClient); - services.AddSingleton(contactService); services.AddSingleton(userDirectory); services.AddTransient(); services.AddTransient(); diff --git a/src/PostIt/PostIt/Helpers/ViewModelBaseHelpers.cs b/src/PostIt/PostIt/Helpers/ViewModelBaseHelpers.cs index 3cb00301..e4250cbb 100644 --- a/src/PostIt/PostIt/Helpers/ViewModelBaseHelpers.cs +++ b/src/PostIt/PostIt/Helpers/ViewModelBaseHelpers.cs @@ -10,7 +10,7 @@ public static class ViewModelBaseHelpers { public static async Task PushPageAsync(this App app, ViewModelBase vm) { - var window = app.Window; + var window = app.View; if (window is null) { throw new InvalidOperationException("MainWindow is not initialized yet."); diff --git a/src/PostIt/PostIt/PostIt.csproj b/src/PostIt/PostIt/PostIt.csproj index 70bd72ca..bde8fd41 100644 --- a/src/PostIt/PostIt/PostIt.csproj +++ b/src/PostIt/PostIt/PostIt.csproj @@ -28,7 +28,6 @@ All - diff --git a/src/PostIt/PostIt/Services/ContactService.Desktop.cs b/src/PostIt/PostIt/Services/ContactService.Desktop.cs deleted file mode 100644 index fa7d37f6..00000000 --- a/src/PostIt/PostIt/Services/ContactService.Desktop.cs +++ /dev/null @@ -1,36 +0,0 @@ -#if !ANDROID && !IOS -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; - -namespace PostIt.Services; - -/// -/// Desktop stub for . -/// -/// The desktop has no equivalent of the mobile address -/// book (no Contacts.Default, no CardDAV out of the -/// box). Rather than synthesise a list from a different -/// source, this provider returns an empty list and lets the -/// UI render an honest "no local contacts on this platform" -/// message. -/// -/// If desktop users want to invite people who aren't -/// Yavsc members, that flow goes through a separate path -/// (manual email entry + invitation endpoint) — not through -/// . Finding existing Yavsc -/// members is 's job, not this -/// one's. -/// -/// Future CardDAV / Google Contacts / Exchange -/// providers can plug in here as additional -/// implementations selected -/// from DI by configuration. -/// -public sealed class ContactService : IContactService -{ - public Task> GetDeviceContactsAsync(CancellationToken ct = default) - => Task.FromResult>(Array.Empty()); -} -#endif diff --git a/src/PostIt/PostIt/Views/MainPage.axaml b/src/PostIt/PostIt/Views/MainPage.axaml index fd75d403..e44f9f99 100644 --- a/src/PostIt/PostIt/Views/MainPage.axaml +++ b/src/PostIt/PostIt/Views/MainPage.axaml @@ -97,23 +97,15 @@ - - + diff --git a/src/PostIt/PostIt/Views/MainView.axaml b/src/PostIt/PostIt/Views/MainView.axaml new file mode 100644 index 00000000..643c0f20 --- /dev/null +++ b/src/PostIt/PostIt/Views/MainView.axaml @@ -0,0 +1,22 @@ + + + + + + + + + + + diff --git a/src/PostIt/PostIt/Views/MainView.axaml.cs b/src/PostIt/PostIt/Views/MainView.axaml.cs new file mode 100644 index 00000000..74f46686 --- /dev/null +++ b/src/PostIt/PostIt/Views/MainView.axaml.cs @@ -0,0 +1,11 @@ +using Avalonia.Controls; + +namespace PostIt.Views; + +public partial class MainView : UserControl +{ + public MainView() + { + InitializeComponent(); + } +} diff --git a/src/PostIt/PostIt/Views/MainWindow.axaml b/src/PostIt/PostIt/Views/MainWindow.axaml index 060e0944..e606cf2b 100644 --- a/src/PostIt/PostIt/Views/MainWindow.axaml +++ b/src/PostIt/PostIt/Views/MainWindow.axaml @@ -7,11 +7,6 @@ mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="PostIt.Views.MainWindow" Icon="/Assets/avalonia-logo.ico" - Title="PostIt" > - - - - - + Title="PostIt"> + diff --git a/src/PostIt/PostIt/Views/MainWindow.axaml.cs b/src/PostIt/PostIt/Views/MainWindow.axaml.cs index 9cb85f55..0dd9280a 100644 --- a/src/PostIt/PostIt/Views/MainWindow.axaml.cs +++ b/src/PostIt/PostIt/Views/MainWindow.axaml.cs @@ -8,4 +8,4 @@ public partial class MainWindow : Window { InitializeComponent(); } -} \ No newline at end of file +} diff --git a/src/PostIt/PostIt/Views/TextEditorBinding.cs b/src/PostIt/PostIt/Views/TextEditorBinding.cs deleted file mode 100644 index 56fda68c..00000000 --- a/src/PostIt/PostIt/Views/TextEditorBinding.cs +++ /dev/null @@ -1,51 +0,0 @@ -using Avalonia; -using Avalonia.Data; -using AvaloniaEdit; - -namespace PostIt.Views; - -public sealed class TextEditorBinding -{ - public static readonly AttachedProperty TextProperty = - AvaloniaProperty.RegisterAttached( - "Text", - defaultBindingMode: BindingMode.TwoWay); - - private static readonly AttachedProperty IsTextChangeSubscribedProperty = - AvaloniaProperty.RegisterAttached("IsTextChangeSubscribed"); - - static TextEditorBinding() - { - TextProperty.Changed.AddClassHandler((editor, args) => - { - EnsureTextChangeSubscribed(editor); - - var text = args.GetNewValue() ?? string.Empty; - if (editor.Text != text) - { - editor.Text = text; - } - }); - } - - public static string? GetText(TextEditor editor) => editor.GetValue(TextProperty); - - public static void SetText(TextEditor editor, string? value) => editor.SetValue(TextProperty, value); - - private static void EnsureTextChangeSubscribed(TextEditor editor) - { - if (editor.GetValue(IsTextChangeSubscribedProperty)) - { - return; - } - - editor.SetValue(IsTextChangeSubscribedProperty, true); - editor.TextChanged += (_, _) => - { - if (editor.Text != GetText(editor)) - { - SetText(editor, editor.Text); - } - }; - } -}