diff --git a/.vscode/launch.json b/.vscode/launch.json index efdaa6ea..2079c716 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -4,6 +4,21 @@ // Pour plus d'informations, visitez : https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ + { + "name": "Debug - Android", + "type": "mono", + "preLaunchTask": "run-debug-android", + "request": "attach", + "address": "localhost", + "port": 10000 + }, + { + "name": "Attach - Android", + "type": "mono", + "request": "attach", + "address": "localhost", + "port": 10000 + }, { "name": "API", "type": "dotnet", @@ -33,12 +48,10 @@ "name": "Test PostIt.Android launch (Xamarin.UITest)", "type": "coreclr", "request": "launch", - "program": "${workspaceFolder}/src/PostIt.Tests/bin/Debug/net10.0/PostIt.Tests.dll", + "program": "${workspaceFolder}/src/PostIt/PostIt.Tests/bin/Debug/net11.0/PostIt.Tests.dll", "args": [ - "--filter-method", - "PostIt.Tests.AndroidAppLaunchTests.PostIt_starts_and_draws_a_first_frame_on_the_emulator" ], - "cwd": "${workspaceFolder}/src/PostIt.Tests", + "cwd": "${workspaceFolder}/src/PostIt/PostIt.Tests", "console": "integratedTerminal", "stopAtEntry": false } diff --git a/.vscode/tasks.json b/.vscode/tasks.json index e45a9921..c900fa6a 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -1,6 +1,29 @@ { "version": "2.0.0", "tasks": [ + { + "label": "run-debug-android", + "command": "dotnet", + "type": "shell", + "options": { + "cwd": "${workspaceFolder}/src/PostIt/PostIt.Android", + "env": { + "DOTNET_HOST_PATH": "/usr/share/dotnet", + "ANDROID_HOME": "/opt/android-sdk", + "JAVA_HOME": "/usr/lib/jvm/java-1.21.0-openjdk-amd64" + } + }, + "args": [ + "build" + "-t:run", + "-p:TargetFramework=net10.0-android", + "-p:Configuration=Debug", + "-p:AndroidAttachDebugger=true", + "-p:AndroidSdbHostPort=10000", + "-p:AndroidSdbTargetPort=10000" + ], + "problemMatcher": "$msCompile" + }, { "label": "build", "command": "dotnet", diff --git a/Makefile b/Makefile index 830c48f2..b086713c 100644 --- a/Makefile +++ b/Makefile @@ -163,7 +163,7 @@ POSTIT_RID ?= android-x64 EMU_HEADLESS ?= 0 LOGCAT_LINES ?= 200 LOGCAT_FOLLOW ?= 0 -LOGCAT_BOOT_WAIT ?= 30 +LOGCAT_BOOT_WAIT ?= 15 POSTIT_ANDROID_CSPROJ := src/PostIt/PostIt.Android/PostIt.Android.csproj POSTIT_APK_DIR := src/PostIt/PostIt.Android/bin/$(CONFIG)/net10.0-android/$(POSTIT_RID) @@ -214,16 +214,17 @@ qemu-build: -p:RuntimeIdentifier=$(POSTIT_RID) \ -p:EmbedAssembliesIntoApk=true \ --nologo - -qemu-install: qemu-build @if [ ! -f "$(POSTIT_APK)" ]; then \ echo " APK not found at $(POSTIT_APK)." >&2; \ echo " Files in $(POSTIT_APK_DIR):" >&2; \ ls -la "$(POSTIT_APK_DIR)" 2>/dev/null || echo " (directory does not exist)" >&2; \ exit 1; \ fi + + +qemu-install: qemu-build @echo " Installing $(POSTIT_APK) on $(ADB_SERIAL)..." - adb -s $(ADB_SERIAL) install -r "$(POSTIT_APK)" + adb -s $(ADB_SERIAL) install -r "$(POSTIT_APK)" -r qemu-uninstall: adb -s $(ADB_SERIAL) uninstall fr.pschneider.PostIt diff --git a/external/dotnet-android-build-image b/external/dotnet-android-build-image deleted file mode 160000 index 0695a6c1..00000000 --- a/external/dotnet-android-build-image +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 0695a6c1fea6508f1a88f7ad0ad9cb93733aa52d diff --git a/src/PostIt/Directory.Packages.props b/src/PostIt/Directory.Packages.props index 38ffe289..2c57fb5f 100644 --- a/src/PostIt/Directory.Packages.props +++ b/src/PostIt/Directory.Packages.props @@ -1,20 +1,36 @@ - + - + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - diff --git a/src/PostIt/PostIt.Android/MainActivity.cs b/src/PostIt/PostIt.Android/MainActivity.cs index 1b413a9f..e85b2dee 100644 --- a/src/PostIt/PostIt.Android/MainActivity.cs +++ b/src/PostIt/PostIt.Android/MainActivity.cs @@ -3,6 +3,9 @@ using Android.Content.PM; using Android.Content; using Avalonia.Android; using AndroidX.Emoji2.Text; +using AndroidX.Core.Provider; +using Android; +using Android.Graphics; namespace PostIt.Android; @@ -26,7 +29,6 @@ public class MainActivity : AvaloniaMainActivity protected override void OnCreate(global::Android.OS.Bundle? savedInstanceState) { - EmojiCompat.Init(this); base.OnCreate(savedInstanceState); PlatformBootstrap.EnsureInitialized(); Current = this; diff --git a/src/PostIt/PostIt.Android/PostIt.Android.csproj b/src/PostIt/PostIt.Android/PostIt.Android.csproj index d0bda3f4..c7202c78 100644 --- a/src/PostIt/PostIt.Android/PostIt.Android.csproj +++ b/src/PostIt/PostIt.Android/PostIt.Android.csproj @@ -1,34 +1,28 @@ Exe - net11.0-android - - android-arm64;android-x64 - 24.0.0 + net10.0-android + 23 enable fr.pschneider.PostIt 1 1.0 apk false - android-arm;android-arm64;android-x64 - 1.1.0.0 - 1.1.0.0 - 1.1.0-beta.1+1.Branch.release-1.0.8-rc1.Sha.1167169aa89e1bf25290e9a152d27b357a500ab3 - 1.1.0-beta.1 Resources\drawable\Icon.png - - - - + + + + + diff --git a/src/PostIt/PostIt.Android/Resources/values/styles.xml b/src/PostIt/PostIt.Android/Resources/values/styles.xml index 44830966..377db44f 100644 --- a/src/PostIt/PostIt.Android/Resources/values/styles.xml +++ b/src/PostIt/PostIt.Android/Resources/values/styles.xml @@ -5,6 +5,7 @@ diff --git a/src/PostIt/PostIt.Android/Services/ContactService.Mobile.cs b/src/PostIt/PostIt.Android/Services/ContactService.Mobile.cs deleted file mode 100644 index c869256d..00000000 --- a/src/PostIt/PostIt.Android/Services/ContactService.Mobile.cs +++ /dev/null @@ -1,84 +0,0 @@ -#if ANDROID || IOS -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.Maui.ApplicationModel.Communication; -using Microsoft.Maui.ApplicationModel; -using Microsoft.Maui.Devices; -using PostIt.Services; -using System.Linq; - -namespace PostIt.Android.Services; - -/// -/// Mobile implementation backed by MAUI Essentials -/// Contacts.Default. -/// -/// Compiled only for ANDROID and IOS. On desktop targets, -/// see ContactService.Desktop.cs (the stub that wins at -/// compile time). -/// -/// Note: at runtime, this class throws -/// NotImplementedInReferenceAssemblyException unless -/// the host application project also references the -/// platform-specific Microsoft.Maui.Essentials implementation -/// (typically PostIt.Android). On iOS the same is -/// required via PostIt.iOS. On desktop the stub is used -/// and this file is excluded. -/// -public sealed class ContactService : IContactService -{ - public async Task> GetDeviceContactsAsync(CancellationToken ct = default) - { - if (DeviceInfo.Current.Platform == DevicePlatform.Unknown) - return Array.Empty(); - - try - { - var status = await Permissions.RequestAsync(); - if (status != PermissionStatus.Granted) - return Array.Empty(); - - var contacts = await Contacts.Default.GetAllAsync(); - if (contacts is null) return Array.Empty(); - - // Carry the per-contact email list as-is. A real - // device contact can carry several addresses (home / - // work / other); the UI use case ("invite / add to a - // circle") can then decide which address to use, or - // let the user pick. The platform-neutral ContactDto - // shape is intentionally richer than the Yavsc - // directory's single-Email shape — the two flows - // answer different questions. - var result = new List(contacts.Count()); - foreach (var c in contacts) - { - var emails = ExtractEmails(c.Emails); - result.Add(new ContactDto( - c.Id, - c.DisplayName ?? string.Empty, - emails)); - } - return result; - } - catch (Exception ex) - { - System.Diagnostics.Debug.WriteLine($"ContactService: {ex.Message}"); - return Array.Empty(); - } - } - - private static IReadOnlyList ExtractEmails(IEnumerable? emails) - { - if (emails is null) return Array.Empty(); - var list = new List(); - foreach (var e in emails) - { - if (!string.IsNullOrEmpty(e.EmailAddress)) - list.Add(e.EmailAddress); - } - return list; - } -} -#endif diff --git a/src/PostIt/PostIt.Browser/PostIt.Browser.csproj b/src/PostIt/PostIt.Browser/PostIt.Browser.csproj index edbc9227..917ba0ab 100644 --- a/src/PostIt/PostIt.Browser/PostIt.Browser.csproj +++ b/src/PostIt/PostIt.Browser/PostIt.Browser.csproj @@ -1,6 +1,6 @@ - net11.0-browser + net10.0-browser Exe true enable diff --git a/src/PostIt/PostIt.Desktop/PostIt.Desktop.csproj b/src/PostIt/PostIt.Desktop/PostIt.Desktop.csproj index 3baf69f5..2982ae29 100644 --- a/src/PostIt/PostIt.Desktop/PostIt.Desktop.csproj +++ b/src/PostIt/PostIt.Desktop/PostIt.Desktop.csproj @@ -3,7 +3,7 @@ WinExe - net11.0 + net10.0 enable 1.1.0.0 1.1.0.0 diff --git a/src/PostIt/PostIt/App.axaml.cs b/src/PostIt/PostIt/App.axaml.cs index d2399873..4161635d 100644 --- a/src/PostIt/PostIt/App.axaml.cs +++ b/src/PostIt/PostIt/App.axaml.cs @@ -27,7 +27,7 @@ public partial class App : Application /// DataValidationErrors.SetErrors. /// public IServiceProvider? ServiceProvider { get; private set; } - private MainWindow window; + public App() { } @@ -35,6 +35,9 @@ public partial class App : Application public override void Initialize() { AvaloniaXamlLoader.Load(this); +#if DEBUG + this.AttachDeveloperTools(); +#endif } public override void OnFrameworkInitializationCompleted() @@ -52,8 +55,6 @@ public partial class App : Application this.ServiceProvider = BuildServices(new ServiceCollection()); AttachServiceProvider(ServiceProvider); var settings = ServiceProvider.GetRequiredService(); - var sessionStatus = ServiceProvider.GetRequiredService(); - var api = ServiceProvider.GetRequiredService(); DataTemplates.Clear(); DataTemplates.Add(new ViewLocator(ServiceProvider)); @@ -85,47 +86,44 @@ public partial class App : Application } }; + if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { - var homeVm = ServiceProvider.GetRequiredService(); - - window = new MainWindow(); - window.SessionBanner.DataContext = sessionStatus; - - // Build the navigation stack from scratch: HomePage is the - // root in both cases. App.BootAsync will push MainPage on - // top if the silent refresh succeeds. - desktop.MainWindow = window; - _ = PushPageAsync(homeVm); - - // When the user logs out, route back to HomePage. We - // ReplaceAsync the current top so we don't grow the stack - // on every logout — otherwise repeated login/logout would - // eventually balloon the back history. - sessionStatus.LogoutCompleted += () => - { - var w = (MainWindow)((IClassicDesktopStyleApplicationLifetime)ApplicationLifetime!).MainWindow!; - var nav = w.NavRoot; - _ = nav.PopToRootAsync(); - }; - - // When the user signs in interactively (Login button on - // the session banner), push MainPage on top of HomePage. - sessionStatus.LoginSucceeded += () => - { - var w = (MainWindow)((IClassicDesktopStyleApplicationLifetime)ApplicationLifetime!).MainWindow!; - _ = PushMainPageAsync(); - }; - - window.Opened += async (_, _) => await BootAsync(this.ServiceProvider, api); + desktop.MainWindow = CreateMainWindow(); } - else if (ApplicationLifetime is ISingleViewApplicationLifetime singleView) + else if (ApplicationLifetime is IActivityApplicationLifetime singleViewFactoryApplicationLifetime) { - singleView.MainView = new MainWindow - { - DataContext = ServiceProvider.GetRequiredService() - }; + singleViewFactoryApplicationLifetime.MainViewFactory = () => CreateMainWindow(); } + else if (ApplicationLifetime is ISingleViewApplicationLifetime singleViewPlatform) + { + singleViewPlatform.MainView = CreateMainWindow(); + } + base.OnFrameworkInitializationCompleted(); + } + + MainWindow window; + 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(); + }; + + var homeVm = ServiceProvider!.GetRequiredService(); + + this.PushPageAsync(homeVm).Wait(); + window.SessionBanner.DataContext = sessionStatus; + return window; } /// @@ -156,7 +154,6 @@ public partial class App : Application var contactService = new ContactService(); var userDirectory = new UserDirectory(userSearchClient); - // Vues services.AddTransient(); // SettingsPage is a singleton: there must be one and only one @@ -268,8 +265,8 @@ public partial class App : Application /// public static Task PushMainPageAsync() { - var app = (App)Current; - var mainVm = app.ServiceProvider.GetRequiredService(); + var app = (App)Current!; + var mainVm = app.ServiceProvider!.GetRequiredService(); return app.PushPageAsync(mainVm); } @@ -310,7 +307,7 @@ public partial class App : Application _ = PushPageAsync(vm); } - internal Task PushPageAsync(ViewModelBase vm) + internal async Task PushPageAsync(ViewModelBase vm) { if (window is null) { @@ -344,10 +341,10 @@ public partial class App : Application var stack = window.NavRoot.NavigationStack; if (stack.Count > 0 && ReferenceEquals(stack[stack.Count - 1], page)) { - return Task.CompletedTask; + return; } - return window.NavRoot.PushAsync(page); + await window.NavRoot.PushAsync(page); } internal async Task GoBackAsync() diff --git a/src/PostIt/PostIt/PostIt.csproj b/src/PostIt/PostIt/PostIt.csproj index 0277d2f6..1b48c21f 100644 --- a/src/PostIt/PostIt/PostIt.csproj +++ b/src/PostIt/PostIt/PostIt.csproj @@ -1,6 +1,6 @@ - net11.0 + net10.0 enable latest true diff --git a/src/PostIt/PostIt/Settings/AuthenticationSettings.cs b/src/PostIt/PostIt/Settings/AuthenticationSettings.cs index ad71063b..99358cfb 100644 --- a/src/PostIt/PostIt/Settings/AuthenticationSettings.cs +++ b/src/PostIt/PostIt/Settings/AuthenticationSettings.cs @@ -21,6 +21,9 @@ public partial class AuthenticationSettings : ObservableObject public static string DefaultAuthority { get; internal set; } = "https://yavsc.pschneider.fr"; public static string DefaultClientId { get; internal set; } = "postit"; + + public static string[] DefaultScopes { get; set; } = { "blogs"} ; + [ObservableProperty] public partial string Authority { get; set; } diff --git a/src/PostIt/PostIt/ViewModels/MainPageViewModel.cs b/src/PostIt/PostIt/ViewModels/MainPageViewModel.cs index d374c9e4..ae5b0f63 100644 --- a/src/PostIt/PostIt/ViewModels/MainPageViewModel.cs +++ b/src/PostIt/PostIt/ViewModels/MainPageViewModel.cs @@ -122,8 +122,8 @@ public partial class MainPageViewModel : ViewModelBase public MainPageViewModel() { - Init(null); SettingsModel = new Settings(); + Init(SettingsModel); BlogClient = null; } @@ -135,6 +135,11 @@ public partial class MainPageViewModel : ViewModelBase SelectedPost = null; IsBusy = false; StatusMessage = "Ready"; + Settings = settings ?? new Settings(); + WindowTitle = "PostIt"; + DraftTitle = string.Empty; + DraftArticle = string.Empty; + DraftIsPublished = false; // Production path: DI injects the canonical Settings singleton // and we use it as-is. Test path: tests call this constructor // without a Settings argument; we fall back to a fresh @@ -145,11 +150,7 @@ public partial class MainPageViewModel : ViewModelBase // sink; that crash is fixed in Settings.OnPropertyChanged // (thread-safe dispatcher marshalling) so the duplicate // instance is now merely wasteful, not dangerous. - Settings = settings ?? new Settings(); - WindowTitle = "PostIt"; - DraftTitle = string.Empty; - DraftArticle = string.Empty; - DraftIsPublished = false; + } /// Save is enabled as soon as the user has typed @@ -174,7 +175,6 @@ public partial class MainPageViewModel : ViewModelBase SettingsModel = new Settings(); BlogClient = blogClient ?? throw new ArgumentNullException(nameof(blogClient)); ; Services = services; - Init(settings); } @@ -210,7 +210,7 @@ public partial class MainPageViewModel : ViewModelBase { await ExecuteAsync(async () => { - var posts = await BlogClient.GetPostsAsync(); + var posts = await BlogClient!.GetPostsAsync(); Posts.Clear(); foreach (var post in posts.OrderByDescending(p => p.DateModified)) { @@ -259,7 +259,7 @@ public partial class MainPageViewModel : ViewModelBase DateCreated = DateTime.UtcNow, DateModified = DateTime.UtcNow, }; - var created = await BlogClient.CreatePostAsync(draft); + var created = await BlogClient!.CreatePostAsync(draft); if (created is not null) { SelectedPost = created; @@ -278,7 +278,7 @@ public partial class MainPageViewModel : ViewModelBase DateCreated = SelectedPost.DateCreated, DateModified = DateTime.UtcNow, }; - await BlogClient.UpdatePostAsync(SelectedPost.Id, update); + await BlogClient!.UpdatePostAsync(SelectedPost.Id, update); StatusMessage = $"Saved post {SelectedPost.Id}."; } @@ -297,7 +297,7 @@ public partial class MainPageViewModel : ViewModelBase await ExecuteAsync(async () => { - await BlogClient.DeletePostAsync(SelectedPost.Id); + await BlogClient!.DeletePostAsync(SelectedPost.Id); StatusMessage = $"Deleted post {SelectedPost.Id}."; SelectedPost = null; await RefreshPostsAsync(); @@ -331,7 +331,7 @@ public partial class MainPageViewModel : ViewModelBase await ExecuteAsync(async () => { var desired = !DraftIsPublished; - await BlogClient.SetPublishAsync(SelectedPost.Id, desired); + await BlogClient!.SetPublishAsync(SelectedPost.Id, desired); DraftIsPublished = desired; // Mirror into the selected post so a subsequent // RefreshPostsAsync() doesn't blow away the @@ -372,7 +372,7 @@ public partial class MainPageViewModel : ViewModelBase private async Task RefreshPostsAsync() { - var posts = await BlogClient.GetPostsAsync(); + var posts = await BlogClient!.GetPostsAsync(); Posts.Clear(); foreach (var post in posts.OrderByDescending(p => p.DateModified)) { diff --git a/src/PostIt/PostIt/ViewModels/Settings.cs b/src/PostIt/PostIt/ViewModels/Settings.cs index 890ca15c..9b54a842 100644 --- a/src/PostIt/PostIt/ViewModels/Settings.cs +++ b/src/PostIt/PostIt/ViewModels/Settings.cs @@ -350,15 +350,14 @@ public partial class Settings : ViewModelBase var settings = JsonSerializer.Deserialize(json); if (settings is null) { - Console.Error.WriteLine($"🩎 Settings payload is invalid (source: {source})."); - return; + UseDefaultSettings(); } // Apply under the gate so concurrent Load() callers cannot // see half the new values / half the old ones. The actual // PropertyChanged fan-out is handled by [ObservableProperty]'s // setters which we route through SetProperty → OnPropertyChanged // → our overridden dispatcher-safe marshaller below. - lock (_mutationGate) + else lock (_mutationGate) { this.Authentication = settings.Authentication; this.DarkMode = settings.DarkMode; @@ -371,6 +370,11 @@ public partial class Settings : ViewModelBase AuthenticationSettings.DefaultClientId : settings.Authentication.ClientId; this.Authentication.RedirectUri = string.IsNullOrWhiteSpace(settings.Authentication.RedirectUri) ? AuthenticationSettings.DefaultDesktopRedirectUri : settings.Authentication.RedirectUri; + if (settings.Authentication.Scopes is null || settings.Authentication.Scopes.Length == 0) + { + settings.Authentication.Scopes = AuthenticationSettings.DefaultScopes; + } + else this.Authentication.Scopes = settings.Authentication.Scopes; } } @@ -400,6 +404,18 @@ public partial class Settings : ViewModelBase } } + private void UseDefaultSettings() + { + this.Authentication = new AuthenticationSettings + { + Authority = AuthenticationSettings.DefaultAuthority, + ClientId = AuthenticationSettings.DefaultClientId, + RedirectUri = AuthenticationSettings.DefaultDesktopRedirectUri, + Scopes = AuthenticationSettings.DefaultScopes + }; + this.DarkMode = false; + } + /// /// Persist the current in-memory state to /// ~/.config/PostIt/postit-settings.json (Linux) / diff --git a/src/Yavsc.Abstract/Yavsc.Abstract.csproj b/src/Yavsc.Abstract/Yavsc.Abstract.csproj index 23297848..f76e42fd 100644 --- a/src/Yavsc.Abstract/Yavsc.Abstract.csproj +++ b/src/Yavsc.Abstract/Yavsc.Abstract.csproj @@ -1,6 +1,6 @@ - net11.0 + net10.0 enable A shared model for a little client/server app, dealing about establishing some contract, between some human client and provider. diff --git a/src/Yavsc.Api.Client/Yavsc.Api.Client.csproj b/src/Yavsc.Api.Client/Yavsc.Api.Client.csproj index be27960c..00e6e2db 100644 --- a/src/Yavsc.Api.Client/Yavsc.Api.Client.csproj +++ b/src/Yavsc.Api.Client/Yavsc.Api.Client.csproj @@ -1,6 +1,6 @@ - net11.0 + net10.0 enable Yavsc.Api.Client Yavsc.Api.Client diff --git a/src/Yavsc.Api/Yavsc.Api.csproj b/src/Yavsc.Api/Yavsc.Api.csproj index 36a96b8b..d9a814f6 100644 --- a/src/Yavsc.Api/Yavsc.Api.csproj +++ b/src/Yavsc.Api/Yavsc.Api.csproj @@ -1,6 +1,6 @@ - net11.0 + net10.0 enable 1c73094f-959f-4211-b1a1-6a69b236c283 Yavsc.Api diff --git a/src/Yavsc.Blogs.Tests/Yavsc.Blogs.Tests.csproj b/src/Yavsc.Blogs.Tests/Yavsc.Blogs.Tests.csproj index e688f730..83c0dc37 100644 --- a/src/Yavsc.Blogs.Tests/Yavsc.Blogs.Tests.csproj +++ b/src/Yavsc.Blogs.Tests/Yavsc.Blogs.Tests.csproj @@ -1,6 +1,6 @@ - net11.0 + net10.0 enable enable false diff --git a/src/Yavsc.Blogs/Yavsc.Blogs.csproj b/src/Yavsc.Blogs/Yavsc.Blogs.csproj index 60f74e06..63b3d977 100644 --- a/src/Yavsc.Blogs/Yavsc.Blogs.csproj +++ b/src/Yavsc.Blogs/Yavsc.Blogs.csproj @@ -1,6 +1,6 @@ - net11.0 + net10.0 enable 1c73094f-959f-4211-b1a1-6a69b236c283 Yavsc.Blogs diff --git a/src/Yavsc.Org.Tests/Yavsc.Org.Tests.csproj b/src/Yavsc.Org.Tests/Yavsc.Org.Tests.csproj index 41c172a6..d332d250 100644 --- a/src/Yavsc.Org.Tests/Yavsc.Org.Tests.csproj +++ b/src/Yavsc.Org.Tests/Yavsc.Org.Tests.csproj @@ -1,6 +1,6 @@ - net11.0 + net10.0 enable enable false diff --git a/src/Yavsc.Org/Yavsc.Org.csproj b/src/Yavsc.Org/Yavsc.Org.csproj index fc633f8a..0403c7eb 100644 --- a/src/Yavsc.Org/Yavsc.Org.csproj +++ b/src/Yavsc.Org/Yavsc.Org.csproj @@ -1,6 +1,6 @@ - net11.0 + net10.0 enable WTFPL 76e56fc2-1619-40d8-8393-365258b7a21d diff --git a/src/Yavsc.Server/Yavsc.Server.csproj b/src/Yavsc.Server/Yavsc.Server.csproj index d47246b6..ac9380a4 100644 --- a/src/Yavsc.Server/Yavsc.Server.csproj +++ b/src/Yavsc.Server/Yavsc.Server.csproj @@ -1,6 +1,6 @@ - net11.0 + net10.0 enable 53bd70e8-ff81-497a-847f-a15fd8ea7a09 Yavsc.Server diff --git a/src/Yavsc.Tests.Shared/Yavsc.Tests.Shared.csproj b/src/Yavsc.Tests.Shared/Yavsc.Tests.Shared.csproj index bd4a6555..6ccd44c0 100644 --- a/src/Yavsc.Tests.Shared/Yavsc.Tests.Shared.csproj +++ b/src/Yavsc.Tests.Shared/Yavsc.Tests.Shared.csproj @@ -1,6 +1,6 @@ - net11.0 + net10.0 enable enable false diff --git a/src/cli/cli.csproj b/src/cli/cli.csproj index 0466998c..010c4eaf 100644 --- a/src/cli/cli.csproj +++ b/src/cli/cli.csproj @@ -1,7 +1,7 @@ Exe - net11.0 + net10.0 enable Yavsc.cli true