From 32832d886b975a44dfa6c222ea86d13703ed18ac Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 12 Sep 2024 19:59:09 +0200 Subject: [PATCH 01/13] Adding Avalonia sample --- samples/todoapp/Samples.TodoApp.sln | 97 ++++ samples/todoapp/TodoApp.Avalonia/.gitignore | 454 ++++++++++++++++++ .../TodoApp.Avalonia/Directory.Build.props | 6 + .../TodoApp.Avalonia.Android/Icon.png | Bin 0 -> 14349 bytes .../TodoApp.Avalonia.Android/MainActivity.cs | 21 + .../Properties/AndroidManifest.xml | 5 + .../Resources/AboutResources.txt | 44 ++ .../drawable-night-v31/avalonia_anim.xml | 66 +++ .../Resources/drawable-v31/avalonia_anim.xml | 71 +++ .../Resources/drawable/splash_screen.xml | 13 + .../Resources/values-night/colors.xml | 4 + .../Resources/values-v31/styles.xml | 21 + .../Resources/values/colors.xml | 4 + .../Resources/values/styles.xml | 12 + .../TodoApp.Avalonia.Android.csproj | 28 ++ .../TodoApp.Avalonia.Browser/Program.cs | 17 + .../Properties/AssemblyInfo.cs | 1 + .../Properties/launchSettings.json | 13 + .../TodoApp.Avalonia.Browser.csproj | 15 + .../runtimeconfig.template.json | 10 + .../TodoApp.Avalonia.Browser/wwwroot/app.css | 58 +++ .../wwwroot/favicon.ico | Bin 0 -> 176111 bytes .../wwwroot/index.html | 36 ++ .../TodoApp.Avalonia.Browser/wwwroot/main.js | 13 + .../TodoApp.Avalonia.Desktop/Program.cs | 21 + .../TodoApp.Avalonia.Desktop.csproj | 24 + .../TodoApp.Avalonia.Desktop/app.manifest | 18 + .../TodoApp.Avalonia.iOS/AppDelegate.cs | 23 + .../TodoApp.Avalonia.iOS/Entitlements.plist | 5 + .../TodoApp.Avalonia.iOS/Info.plist | 43 ++ .../TodoApp.Avalonia.iOS/Main.cs | 14 + .../Resources/LaunchScreen.xib | 43 ++ .../TodoApp.Avalonia.iOS.csproj | 16 + .../TodoApp.Avalonia/TodoApp.Avalonia.sln | 54 +++ .../TodoApp.Avalonia/App.axaml | 10 + .../TodoApp.Avalonia/App.axaml.cs | 107 +++++ .../TodoApp.Avalonia/Assets/avalonia-logo.ico | Bin 0 -> 176111 bytes .../TodoApp.Avalonia/Database/AppDbContext.cs | 39 ++ .../Database/DbContextInitializer.cs | 29 ++ .../Database/IDbInitializer.cs | 26 + .../Database/OfflineClientEntry.cs | 20 + .../TodoApp.Avalonia/Database/ToDoItem.cs | 11 + .../Services/DialogManager.cs | 108 +++++ .../TodoApp.Avalonia/TodoApp.Avalonia.csproj | 25 + .../ViewModels/TodoItemViewModel.cs | 62 +++ .../ViewModels/TodoListViewModel.cs | 133 +++++ .../ViewModels/ViewModelBase.cs | 7 + .../TodoApp.Avalonia/Views/MainView.axaml | 65 +++ .../TodoApp.Avalonia/Views/MainView.axaml.cs | 11 + .../TodoApp.Avalonia/Views/MainWindow.axaml | 12 + .../Views/MainWindow.axaml.cs | 11 + 51 files changed, 1946 insertions(+) create mode 100644 samples/todoapp/TodoApp.Avalonia/.gitignore create mode 100644 samples/todoapp/TodoApp.Avalonia/Directory.Build.props create mode 100644 samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Android/Icon.png create mode 100644 samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Android/MainActivity.cs create mode 100644 samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Android/Properties/AndroidManifest.xml create mode 100644 samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Android/Resources/AboutResources.txt create mode 100644 samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Android/Resources/drawable-night-v31/avalonia_anim.xml create mode 100644 samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Android/Resources/drawable-v31/avalonia_anim.xml create mode 100644 samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Android/Resources/drawable/splash_screen.xml create mode 100644 samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Android/Resources/values-night/colors.xml create mode 100644 samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Android/Resources/values-v31/styles.xml create mode 100644 samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Android/Resources/values/colors.xml create mode 100644 samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Android/Resources/values/styles.xml create mode 100644 samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Android/TodoApp.Avalonia.Android.csproj create mode 100644 samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Browser/Program.cs create mode 100644 samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Browser/Properties/AssemblyInfo.cs create mode 100644 samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Browser/Properties/launchSettings.json create mode 100644 samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Browser/TodoApp.Avalonia.Browser.csproj create mode 100644 samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Browser/runtimeconfig.template.json create mode 100644 samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Browser/wwwroot/app.css create mode 100644 samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Browser/wwwroot/favicon.ico create mode 100644 samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Browser/wwwroot/index.html create mode 100644 samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Browser/wwwroot/main.js create mode 100644 samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Desktop/Program.cs create mode 100644 samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Desktop/TodoApp.Avalonia.Desktop.csproj create mode 100644 samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Desktop/app.manifest create mode 100644 samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.iOS/AppDelegate.cs create mode 100644 samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.iOS/Entitlements.plist create mode 100644 samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.iOS/Info.plist create mode 100644 samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.iOS/Main.cs create mode 100644 samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.iOS/Resources/LaunchScreen.xib create mode 100644 samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.iOS/TodoApp.Avalonia.iOS.csproj create mode 100644 samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.sln create mode 100644 samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/App.axaml create mode 100644 samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/App.axaml.cs create mode 100644 samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Assets/avalonia-logo.ico create mode 100644 samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/AppDbContext.cs create mode 100644 samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/DbContextInitializer.cs create mode 100644 samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/IDbInitializer.cs create mode 100644 samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/OfflineClientEntry.cs create mode 100644 samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/ToDoItem.cs create mode 100644 samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Services/DialogManager.cs create mode 100644 samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/TodoApp.Avalonia.csproj create mode 100644 samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoItemViewModel.cs create mode 100644 samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoListViewModel.cs create mode 100644 samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/ViewModelBase.cs create mode 100644 samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Views/MainView.axaml create mode 100644 samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Views/MainView.axaml.cs create mode 100644 samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Views/MainWindow.axaml create mode 100644 samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Views/MainWindow.axaml.cs diff --git a/samples/todoapp/Samples.TodoApp.sln b/samples/todoapp/Samples.TodoApp.sln index 1204e402..44851fab 100644 --- a/samples/todoapp/Samples.TodoApp.sln +++ b/samples/todoapp/Samples.TodoApp.sln @@ -15,6 +15,18 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TodoApp.MAUI", "TodoApp.MAU EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TodoApp.WPF", "TodoApp.WPF\TodoApp.WPF.csproj", "{A0996FB8-890D-4E90-A881-01F9EF709711}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TodoApp.Avalonia", "TodoApp.Avalonia", "{9A8B7D7F-1AF1-4C1C-A74A-E422BB680C6E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TodoApp.Avalonia", "TodoApp.Avalonia\TodoApp.Avalonia\TodoApp.Avalonia.csproj", "{539C6E0F-8F23-4AE0-B8E6-7E72C53B890A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TodoApp.Avalonia.Android", "TodoApp.Avalonia\TodoApp.Avalonia.Android\TodoApp.Avalonia.Android.csproj", "{9C2BA2A4-4AD6-4B67-BB6B-29A9024C33C4}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TodoApp.Avalonia.Desktop", "TodoApp.Avalonia\TodoApp.Avalonia.Desktop\TodoApp.Avalonia.Desktop.csproj", "{3D741850-6FAA-4F36-BD58-F6ECE0CE55D7}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TodoApp.Avalonia.iOS", "TodoApp.Avalonia\TodoApp.Avalonia.iOS\TodoApp.Avalonia.iOS.csproj", "{DFCE2057-9F7B-4E1A-9C83-B524D9A82FF1}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TodoApp.Avalonia.Browser", "TodoApp.Avalonia\TodoApp.Avalonia.Browser\TodoApp.Avalonia.Browser.csproj", "{E8BB1310-477D-44B0-B13E-77F09433D0A3}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -123,12 +135,97 @@ Global {A0996FB8-890D-4E90-A881-01F9EF709711}.Release|x64.Build.0 = Release|Any CPU {A0996FB8-890D-4E90-A881-01F9EF709711}.Release|x86.ActiveCfg = Release|Any CPU {A0996FB8-890D-4E90-A881-01F9EF709711}.Release|x86.Build.0 = Release|Any CPU + {539C6E0F-8F23-4AE0-B8E6-7E72C53B890A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {539C6E0F-8F23-4AE0-B8E6-7E72C53B890A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {539C6E0F-8F23-4AE0-B8E6-7E72C53B890A}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {539C6E0F-8F23-4AE0-B8E6-7E72C53B890A}.Debug|ARM64.Build.0 = Debug|Any CPU + {539C6E0F-8F23-4AE0-B8E6-7E72C53B890A}.Debug|x64.ActiveCfg = Debug|Any CPU + {539C6E0F-8F23-4AE0-B8E6-7E72C53B890A}.Debug|x64.Build.0 = Debug|Any CPU + {539C6E0F-8F23-4AE0-B8E6-7E72C53B890A}.Debug|x86.ActiveCfg = Debug|Any CPU + {539C6E0F-8F23-4AE0-B8E6-7E72C53B890A}.Debug|x86.Build.0 = Debug|Any CPU + {539C6E0F-8F23-4AE0-B8E6-7E72C53B890A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {539C6E0F-8F23-4AE0-B8E6-7E72C53B890A}.Release|Any CPU.Build.0 = Release|Any CPU + {539C6E0F-8F23-4AE0-B8E6-7E72C53B890A}.Release|ARM64.ActiveCfg = Release|Any CPU + {539C6E0F-8F23-4AE0-B8E6-7E72C53B890A}.Release|ARM64.Build.0 = Release|Any CPU + {539C6E0F-8F23-4AE0-B8E6-7E72C53B890A}.Release|x64.ActiveCfg = Release|Any CPU + {539C6E0F-8F23-4AE0-B8E6-7E72C53B890A}.Release|x64.Build.0 = Release|Any CPU + {539C6E0F-8F23-4AE0-B8E6-7E72C53B890A}.Release|x86.ActiveCfg = Release|Any CPU + {539C6E0F-8F23-4AE0-B8E6-7E72C53B890A}.Release|x86.Build.0 = Release|Any CPU + {9C2BA2A4-4AD6-4B67-BB6B-29A9024C33C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9C2BA2A4-4AD6-4B67-BB6B-29A9024C33C4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9C2BA2A4-4AD6-4B67-BB6B-29A9024C33C4}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {9C2BA2A4-4AD6-4B67-BB6B-29A9024C33C4}.Debug|ARM64.Build.0 = Debug|Any CPU + {9C2BA2A4-4AD6-4B67-BB6B-29A9024C33C4}.Debug|x64.ActiveCfg = Debug|Any CPU + {9C2BA2A4-4AD6-4B67-BB6B-29A9024C33C4}.Debug|x64.Build.0 = Debug|Any CPU + {9C2BA2A4-4AD6-4B67-BB6B-29A9024C33C4}.Debug|x86.ActiveCfg = Debug|Any CPU + {9C2BA2A4-4AD6-4B67-BB6B-29A9024C33C4}.Debug|x86.Build.0 = Debug|Any CPU + {9C2BA2A4-4AD6-4B67-BB6B-29A9024C33C4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9C2BA2A4-4AD6-4B67-BB6B-29A9024C33C4}.Release|Any CPU.Build.0 = Release|Any CPU + {9C2BA2A4-4AD6-4B67-BB6B-29A9024C33C4}.Release|ARM64.ActiveCfg = Release|Any CPU + {9C2BA2A4-4AD6-4B67-BB6B-29A9024C33C4}.Release|ARM64.Build.0 = Release|Any CPU + {9C2BA2A4-4AD6-4B67-BB6B-29A9024C33C4}.Release|x64.ActiveCfg = Release|Any CPU + {9C2BA2A4-4AD6-4B67-BB6B-29A9024C33C4}.Release|x64.Build.0 = Release|Any CPU + {9C2BA2A4-4AD6-4B67-BB6B-29A9024C33C4}.Release|x86.ActiveCfg = Release|Any CPU + {9C2BA2A4-4AD6-4B67-BB6B-29A9024C33C4}.Release|x86.Build.0 = Release|Any CPU + {3D741850-6FAA-4F36-BD58-F6ECE0CE55D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3D741850-6FAA-4F36-BD58-F6ECE0CE55D7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3D741850-6FAA-4F36-BD58-F6ECE0CE55D7}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {3D741850-6FAA-4F36-BD58-F6ECE0CE55D7}.Debug|ARM64.Build.0 = Debug|Any CPU + {3D741850-6FAA-4F36-BD58-F6ECE0CE55D7}.Debug|x64.ActiveCfg = Debug|Any CPU + {3D741850-6FAA-4F36-BD58-F6ECE0CE55D7}.Debug|x64.Build.0 = Debug|Any CPU + {3D741850-6FAA-4F36-BD58-F6ECE0CE55D7}.Debug|x86.ActiveCfg = Debug|Any CPU + {3D741850-6FAA-4F36-BD58-F6ECE0CE55D7}.Debug|x86.Build.0 = Debug|Any CPU + {3D741850-6FAA-4F36-BD58-F6ECE0CE55D7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3D741850-6FAA-4F36-BD58-F6ECE0CE55D7}.Release|Any CPU.Build.0 = Release|Any CPU + {3D741850-6FAA-4F36-BD58-F6ECE0CE55D7}.Release|ARM64.ActiveCfg = Release|Any CPU + {3D741850-6FAA-4F36-BD58-F6ECE0CE55D7}.Release|ARM64.Build.0 = Release|Any CPU + {3D741850-6FAA-4F36-BD58-F6ECE0CE55D7}.Release|x64.ActiveCfg = Release|Any CPU + {3D741850-6FAA-4F36-BD58-F6ECE0CE55D7}.Release|x64.Build.0 = Release|Any CPU + {3D741850-6FAA-4F36-BD58-F6ECE0CE55D7}.Release|x86.ActiveCfg = Release|Any CPU + {3D741850-6FAA-4F36-BD58-F6ECE0CE55D7}.Release|x86.Build.0 = Release|Any CPU + {DFCE2057-9F7B-4E1A-9C83-B524D9A82FF1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DFCE2057-9F7B-4E1A-9C83-B524D9A82FF1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DFCE2057-9F7B-4E1A-9C83-B524D9A82FF1}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {DFCE2057-9F7B-4E1A-9C83-B524D9A82FF1}.Debug|ARM64.Build.0 = Debug|Any CPU + {DFCE2057-9F7B-4E1A-9C83-B524D9A82FF1}.Debug|x64.ActiveCfg = Debug|Any CPU + {DFCE2057-9F7B-4E1A-9C83-B524D9A82FF1}.Debug|x64.Build.0 = Debug|Any CPU + {DFCE2057-9F7B-4E1A-9C83-B524D9A82FF1}.Debug|x86.ActiveCfg = Debug|Any CPU + {DFCE2057-9F7B-4E1A-9C83-B524D9A82FF1}.Debug|x86.Build.0 = Debug|Any CPU + {DFCE2057-9F7B-4E1A-9C83-B524D9A82FF1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DFCE2057-9F7B-4E1A-9C83-B524D9A82FF1}.Release|Any CPU.Build.0 = Release|Any CPU + {DFCE2057-9F7B-4E1A-9C83-B524D9A82FF1}.Release|ARM64.ActiveCfg = Release|Any CPU + {DFCE2057-9F7B-4E1A-9C83-B524D9A82FF1}.Release|ARM64.Build.0 = Release|Any CPU + {DFCE2057-9F7B-4E1A-9C83-B524D9A82FF1}.Release|x64.ActiveCfg = Release|Any CPU + {DFCE2057-9F7B-4E1A-9C83-B524D9A82FF1}.Release|x64.Build.0 = Release|Any CPU + {DFCE2057-9F7B-4E1A-9C83-B524D9A82FF1}.Release|x86.ActiveCfg = Release|Any CPU + {DFCE2057-9F7B-4E1A-9C83-B524D9A82FF1}.Release|x86.Build.0 = Release|Any CPU + {E8BB1310-477D-44B0-B13E-77F09433D0A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E8BB1310-477D-44B0-B13E-77F09433D0A3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E8BB1310-477D-44B0-B13E-77F09433D0A3}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {E8BB1310-477D-44B0-B13E-77F09433D0A3}.Debug|ARM64.Build.0 = Debug|Any CPU + {E8BB1310-477D-44B0-B13E-77F09433D0A3}.Debug|x64.ActiveCfg = Debug|Any CPU + {E8BB1310-477D-44B0-B13E-77F09433D0A3}.Debug|x64.Build.0 = Debug|Any CPU + {E8BB1310-477D-44B0-B13E-77F09433D0A3}.Debug|x86.ActiveCfg = Debug|Any CPU + {E8BB1310-477D-44B0-B13E-77F09433D0A3}.Debug|x86.Build.0 = Debug|Any CPU + {E8BB1310-477D-44B0-B13E-77F09433D0A3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E8BB1310-477D-44B0-B13E-77F09433D0A3}.Release|Any CPU.Build.0 = Release|Any CPU + {E8BB1310-477D-44B0-B13E-77F09433D0A3}.Release|ARM64.ActiveCfg = Release|Any CPU + {E8BB1310-477D-44B0-B13E-77F09433D0A3}.Release|ARM64.Build.0 = Release|Any CPU + {E8BB1310-477D-44B0-B13E-77F09433D0A3}.Release|x64.ActiveCfg = Release|Any CPU + {E8BB1310-477D-44B0-B13E-77F09433D0A3}.Release|x64.Build.0 = Release|Any CPU + {E8BB1310-477D-44B0-B13E-77F09433D0A3}.Release|x86.ActiveCfg = Release|Any CPU + {E8BB1310-477D-44B0-B13E-77F09433D0A3}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {2AC73FBE-9E76-4702-B551-B5884383CC68} = {7183ECEC-9F44-48CE-BB97-AA2445170D5E} + {539C6E0F-8F23-4AE0-B8E6-7E72C53B890A} = {9A8B7D7F-1AF1-4C1C-A74A-E422BB680C6E} + {9C2BA2A4-4AD6-4B67-BB6B-29A9024C33C4} = {9A8B7D7F-1AF1-4C1C-A74A-E422BB680C6E} + {3D741850-6FAA-4F36-BD58-F6ECE0CE55D7} = {9A8B7D7F-1AF1-4C1C-A74A-E422BB680C6E} + {DFCE2057-9F7B-4E1A-9C83-B524D9A82FF1} = {9A8B7D7F-1AF1-4C1C-A74A-E422BB680C6E} + {E8BB1310-477D-44B0-B13E-77F09433D0A3} = {9A8B7D7F-1AF1-4C1C-A74A-E422BB680C6E} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {91B9DE2A-8B79-4DC4-8235-216CD07F1CB2} diff --git a/samples/todoapp/TodoApp.Avalonia/.gitignore b/samples/todoapp/TodoApp.Avalonia/.gitignore new file mode 100644 index 00000000..8afdcb63 --- /dev/null +++ b/samples/todoapp/TodoApp.Avalonia/.gitignore @@ -0,0 +1,454 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# Tye +.tye/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +## +## Visual studio for Mac +## + + +# globs +Makefile.in +*.userprefs +*.usertasks +config.make +config.status +aclocal.m4 +install-sh +autom4te.cache/ +*.tar.gz +tarballs/ +test-results/ + +# Mac bundle stuff +*.dmg +*.app + +# content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# JetBrains Rider +.idea/ +*.sln.iml + +## +## Visual Studio Code +## +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json diff --git a/samples/todoapp/TodoApp.Avalonia/Directory.Build.props b/samples/todoapp/TodoApp.Avalonia/Directory.Build.props new file mode 100644 index 00000000..89dc4436 --- /dev/null +++ b/samples/todoapp/TodoApp.Avalonia/Directory.Build.props @@ -0,0 +1,6 @@ + + + enable + 11.1.0 + + diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Android/Icon.png b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Android/Icon.png new file mode 100644 index 0000000000000000000000000000000000000000..41a2a618fb02e4cb7f6a15caf572b693bfe1ebb1 GIT binary patch literal 14349 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 +{ + protected override AppBuilder CustomizeAppBuilder(AppBuilder builder) + { + return base.CustomizeAppBuilder(builder) + .WithInterFont(); + } +} \ No newline at end of file diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Android/Properties/AndroidManifest.xml b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Android/Properties/AndroidManifest.xml new file mode 100644 index 00000000..7d86d689 --- /dev/null +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Android/Properties/AndroidManifest.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Android/Resources/AboutResources.txt b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Android/Resources/AboutResources.txt new file mode 100644 index 00000000..c2bca974 --- /dev/null +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Android/Resources/AboutResources.txt @@ -0,0 +1,44 @@ +Images, layout descriptions, binary blobs and string dictionaries can be included +in your application as resource files. Various Android APIs are designed to +operate on the resource IDs instead of dealing with images, strings or binary blobs +directly. + +For example, a sample Android app that contains a user interface layout (main.axml), +an internationalization string table (strings.xml) and some icons (drawable-XXX/icon.png) +would keep its resources in the "Resources" directory of the application: + +Resources/ + drawable/ + icon.png + + layout/ + main.axml + + values/ + strings.xml + +In order to get the build system to recognize Android resources, set the build action to +"AndroidResource". The native Android APIs do not operate directly with filenames, but +instead operate on resource IDs. When you compile an Android application that uses resources, +the build system will package the resources for distribution and generate a class called "R" +(this is an Android convention) that contains the tokens for each one of the resources +included. For example, for the above Resources layout, this is what the R class would expose: + +public class R { + public class drawable { + public const int icon = 0x123; + } + + public class layout { + public const int main = 0x456; + } + + public class strings { + public const int first_string = 0xabc; + public const int second_string = 0xbcd; + } +} + +You would then use R.drawable.icon to reference the drawable/icon.png file, or R.layout.main +to reference the layout/main.axml file, or R.strings.first_string to reference the first +string in the dictionary file values/strings.xml. \ No newline at end of file diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Android/Resources/drawable-night-v31/avalonia_anim.xml b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Android/Resources/drawable-night-v31/avalonia_anim.xml new file mode 100644 index 00000000..dde4b5a7 --- /dev/null +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Android/Resources/drawable-night-v31/avalonia_anim.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Android/Resources/drawable-v31/avalonia_anim.xml b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Android/Resources/drawable-v31/avalonia_anim.xml new file mode 100644 index 00000000..94f27d9e --- /dev/null +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Android/Resources/drawable-v31/avalonia_anim.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Android/Resources/drawable/splash_screen.xml b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Android/Resources/drawable/splash_screen.xml new file mode 100644 index 00000000..2e920b4b --- /dev/null +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Android/Resources/drawable/splash_screen.xml @@ -0,0 +1,13 @@ + + + + + + + + + + diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Android/Resources/values-night/colors.xml b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Android/Resources/values-night/colors.xml new file mode 100644 index 00000000..3d47b6fc --- /dev/null +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Android/Resources/values-night/colors.xml @@ -0,0 +1,4 @@ + + + #212121 + diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Android/Resources/values-v31/styles.xml b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Android/Resources/values-v31/styles.xml new file mode 100644 index 00000000..d5ecec43 --- /dev/null +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Android/Resources/values-v31/styles.xml @@ -0,0 +1,21 @@ + + + + + + + + diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Android/Resources/values/colors.xml b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Android/Resources/values/colors.xml new file mode 100644 index 00000000..59279d5d --- /dev/null +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Android/Resources/values/colors.xml @@ -0,0 +1,4 @@ + + + #FFFFFF + diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Android/Resources/values/styles.xml b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Android/Resources/values/styles.xml new file mode 100644 index 00000000..6e534de2 --- /dev/null +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Android/Resources/values/styles.xml @@ -0,0 +1,12 @@ + + + + + + + diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Android/TodoApp.Avalonia.Android.csproj b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Android/TodoApp.Avalonia.Android.csproj new file mode 100644 index 00000000..ebf47e8e --- /dev/null +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Android/TodoApp.Avalonia.Android.csproj @@ -0,0 +1,28 @@ + + + Exe + net8.0-android + 21 + enable + com.CompanyName.TodoApp.Avalonia + 1 + 1.0 + apk + false + + + + + Resources\drawable\Icon.png + + + + + + + + + + + + diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Browser/Program.cs b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Browser/Program.cs new file mode 100644 index 00000000..996ad395 --- /dev/null +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Browser/Program.cs @@ -0,0 +1,17 @@ +using System.Runtime.Versioning; +using System.Threading.Tasks; +using Avalonia; +using Avalonia.Browser; +using TodoApp.Avalonia; + +[assembly: SupportedOSPlatform("browser")] + +internal sealed partial class Program +{ + private static Task Main(string[] args) => BuildAvaloniaApp() + .WithInterFont() + .StartBrowserAppAsync("out"); + + public static AppBuilder BuildAvaloniaApp() + => AppBuilder.Configure(); +} \ No newline at end of file diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Browser/Properties/AssemblyInfo.cs b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Browser/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..f31aed8e --- /dev/null +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Browser/Properties/AssemblyInfo.cs @@ -0,0 +1 @@ +[assembly: System.Runtime.Versioning.SupportedOSPlatform("browser")] \ No newline at end of file diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Browser/Properties/launchSettings.json b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Browser/Properties/launchSettings.json new file mode 100644 index 00000000..19a2eadf --- /dev/null +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Browser/Properties/launchSettings.json @@ -0,0 +1,13 @@ +{ + "profiles": { + "TodoApp.Avalonia.Browser": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:7169;http://localhost:5235", + "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", + } + } +} diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Browser/TodoApp.Avalonia.Browser.csproj b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Browser/TodoApp.Avalonia.Browser.csproj new file mode 100644 index 00000000..9879acbd --- /dev/null +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Browser/TodoApp.Avalonia.Browser.csproj @@ -0,0 +1,15 @@ + + + net8.0-browser + Exe + true + + + + + + + + + + diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Browser/runtimeconfig.template.json b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Browser/runtimeconfig.template.json new file mode 100644 index 00000000..b96a9432 --- /dev/null +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Browser/runtimeconfig.template.json @@ -0,0 +1,10 @@ +{ + "wasmHostProperties": { + "perHostConfig": [ + { + "name": "browser", + "host": "browser" + } + ] + } +} \ No newline at end of file diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Browser/wwwroot/app.css b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Browser/wwwroot/app.css new file mode 100644 index 00000000..1d6f754a --- /dev/null +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Browser/wwwroot/app.css @@ -0,0 +1,58 @@ +/* HTML styles for the splash screen */ +.avalonia-splash { + position: absolute; + height: 100%; + width: 100%; + background: white; + font-family: 'Outfit', sans-serif; + justify-content: center; + align-items: center; + display: flex; + pointer-events: none; +} + +/* Light theme styles */ +@media (prefers-color-scheme: light) { + .avalonia-splash { + background: white; + } + + .avalonia-splash h2 { + color: #1b2a4e; + } + + .avalonia-splash a { + color: #0D6EFD; + } +} + +@media (prefers-color-scheme: dark) { + .avalonia-splash { + background: #1b2a4e; + } + + .avalonia-splash h2 { + color: white; + } + + .avalonia-splash a { + color: white; + } +} + +.avalonia-splash h2 { + font-weight: 400; + font-size: 1.5rem; +} + +.avalonia-splash a { + text-decoration: none; + font-size: 2.5rem; + display: block; +} + +.avalonia-splash.splash-close { + transition: opacity 200ms, display 200ms; + display: none; + opacity: 0; +} diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Browser/wwwroot/favicon.ico b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Browser/wwwroot/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..da8d49ff9b94e52778f5324a1b87dd443a698b57 GIT binary patch literal 176111 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 zds⪻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

r@R8DskCg$QY%d=x6zD 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

!LxQh!NmF zk`(0Tj<ZW5E8&DpXim*G3_g%p~m+WPP3v>mv`TF{tA#CZlAV1iI z$sbTihG%;$dY@ID{z$-{<*^l96ez;5-yPlm9<#0Vp(DmRMjt5}mO&)*|Ao}9w1NT!U!3v{BR>pG3m4dvAv-jR< zR##iwb^`%3Z8MMRLF*iNu zmF$BJptdopP98FT%?meHALC3)l*?Eak7wgYuQrXJ_Eu;ZwiG;`^w{1|Op42fT9g|_ zsshz40(mPpNJVTIg;l?C(@J!tO!HQn8OY;fg^<T3@U|Sc83Nq zOA#FoV9fdJ-PZT9?Dwwq6Kp+yW$6+j$E+2gEKV)%rCetTnm49eyPU7DZk#q%+pW~y z|B0KsLwG6D4WtEQsJaB!E_;~4mYqb}Yk`PDRW*g$2-eD;kqA^yXCsWBh2TB7O9xEH zMx{eH8;>r~9Zc${$noP^Mu!$ThYQfe*2=(d(b)gw;QQqxDX3?It`b{AekTLUF7Gb?yx`*nAz;?yh5 z7*w$JXKH%7VCZ3i~H`= zlE&Bef$)~x%WH6)Z!*-LrE7XzE52Q^$yk%qEh{E$wz}DjokiB|S1m0hvNysa2*7yx zRs-~^|HTL(s$@{Nh>l8Kiq&75AW8<|9L$KoUWACkuW*yoq&mH?Kuqg+SJ6RO&dhv<{j z_$#!^w$(5>*r|^qC%a+CrN&>={f#9E(8 zJq;|$^KYMHGhb#$GV`L9DA&Tu9WVS=`^R-~QI^QPnguaC>2Sx$j= z-DutV&bp-LooA|saXYm0#D?5tVq=*c1p_JM)&sN!Dh&h8$0s8+pI&UM5-VKtLR^|f zR6s3K=#)Hww>x}V{+W1FY5O9Ni&J-Te0)w}mk>YIY2Ed=li}W)<=Itt!TYdl7=Sh z;#qSU=Y^){>z%OJwY9FtNm9bWx!lVEY)KUXd6US~c+`>?LTC%RKVj5XescPDCNiH? zhV{psT50&XMGX!8$9>GU06DboPbf-;-0P_;zwX6JY=spxmQ`z`k{a_CoKYvuhcgq% zgGHcIBXvS5q}ECb@4U`Uv3cE^d^1{?t!u$Wa;s?YK3?q!GiIHHU~SSePBrQbcrT5l z8M7Uyd3zr$y^wcP^4z>MVgQId{@6WNWId7%zhfB)DWt2*V6E}%sYf?CA#7BqKby!E zU`eWB^{=NNul)2nr$iTYbH8GLlSZZt!UO%d;Gt)uXYZ?PO5s?9?A(C0%~LOn+LFYj zHJ8#<=lC|m+5=%H0=Ljrao{)uL_UwRPr~}iSWP>_`@!$uN^%{oWBg@5H}L$#;Jgdf z!IXj`;4o57A;S-*j_r!|EKOdBhcG&#e_(%em3P_vDnCUDx8|3VoIqSZfy-a4*ZSFi z#>Vwd(~o)X^;%H3HdsLQ)%uy?KJ$Ks4%*DVf(g|Of%ZgWvHhXL5>dX|b=*{QpTuS< zY+o-T7n6<7X)^uUH98tYoijiGlpxU8=iLh%+h`TXTx8j@M=NbKq{zu}{EMHE&bJ&f zAvqz1V6+C09m3dYl2P1^)rViuhQ9oUch_HpDv(~XwWJ(y(Lw-#dmXkHB}mJ|u;={x zv)>iJy8ehjP`Ptfx=}ZLJrfVz4?8rtG}uDPDR%?+|^7l}C~k1Va1A4ABL*j4-5YPgh@0zLBW4rw7M~5mML5 zU!bcsd?0e)a*n=uTDm(cjd0oa)goDH2@JvjqT{!l9z5|MwH$j-HfjtOJPEe6xw&HA zDzIn5mD83mi{T8({+5!(lVr1+%ufiGfG;>$l57u3ymgDvWU zPfwnwk6F#JaGP5ya|5z-+dBNVSr)5JzkXO7?QI@E&vE$e3${65=*1sZ1fr=ziku@< zjp59%EX{DohXgIT^5uS*`h-g$`#Ch7w?%%4F6?c$ta`y)eHe%+QEVtHdycoF>h z>`C=EU!DYpHK9;x@0ss#bP)NseFhK8=&e;J!@F*eTlpZWJDr&>T+)`zhv~xpkd@?P zQ5EB<#nIV{q$a?8i@cpKmgTSwTpjDk!xJBx{Xo}3#vHxLOR>eD{GF$r|E^dK2=taUu+Z1BeUQ&{hSd$r1wazZe!Q@+T17Tv1}>tf2fd$2Nyn?U$JsM zyB!4eW0HQ#l)ln>Wt^!eESx#I=t1!u;(-OR zDi4rxJ1lGCK7(2>UCrQt9fSKQKgXhyV{00YtH5c*kiA?>!o#Y21M6-c>1(GS&vb?F z9yE4|k_CZ*+RTjnz24dQR$62HNpv3@#JNtx=XZhbXU{9Al6fbRd8hr&ge*AL^!A^9 z^U@3Zd)NFe-@uL9Ourm{4U}GIi@g{AN(4zuk}-o1#ck|)%75<}_}9?Q^QNBbQCu&D~>g|fXS&?W#NlX+5tOBn*Rw|xJT!O2)0z3GsE5^92gs8eQHcPOZ6*%RHF^Y6E_UexI^;&$1e65lU8 zzURAt@cfJ0&H~>Rci8bHc)f|H>;S7Splj*yt|YG z`VqJOyMSMgSBmLAC8MjFaf*umWyrGe)rW~+atV$GQ%a2SPii-~BUrA!*VhR?7FL`F zkiI!iUflzM>FUO%`#ASQPuj8XbDU}d<=UNWq%{tXb7F8~VgGVO4K5mhK}0gNTIuVv zbu}2c{L<(GpYN3|^iIlX*9mQd9UZw#X0FREN$XWSt}9&F9ur`kTp}?G0|&AFIObV;}q{3H7ifApmbTo~QAxrwPNsggCKC z%C*}lG-p1?$%34*^c7n7g_zzyPqGA^oWo}amf!`cU~q{Z?|mWzKzMR{I`2Bcef2*k zxF4R>En2%3i^?wLg2~Z{PVHi@}_fmO8#q58n^EZvC zaZGjXuko-eXOFYtQr9!JH92}?8jo^=?2Lwdc^`6cuoE^aT;)rJ3`V|%A-c8Bhn~(C zo-D>^p@?^gq64cD*4jHdGQavS4W?FEo_S-Lui3k^l&Wr_QUGNEe9PeO`;m`1If9`p zR~sKiEWA_qGtY{<*dVIh1)KfnS_Tq1u(iy}Dq<>!jAFkbLdhr-atXfsP5Eclsj!Rh z8|yNiG00v9i|rp@Ixc#0UZ%M=43Mp}#k1XnluVb#$j?kB7?)(1Zr#scqFzJ>;_vug zNTm^g{^aY#2)Lv+x%3)OiJ1ihh^?V(`|)~88X0WDitL_fdOaO3PK?<>K`2g)OXRF} z?yB##-p;0_70X&NTb0T+e4sUy=2sZ|@I0(e9RGZY5mGF;NzOK(^v-Cyxa%F950!K< zXS=z07oU8?QasUbu)6ZpEVK_=11R%L9!%(2PclE#2b6Z9uDD%ams-~BqD5>D6~fGH#FaxfGEwGY)El-(V?X`)dIfhir*9wFvi!M>Hd=|o zZR41~CGOd!&1y}aT=DJx+s2iu3-);X78#0PcPdkg9pokYOz{Kq*UV_+#8yYrmsTI zh{m(w`ao`s0^ek=1|crEcTPYn7kahJ4(OQ-v%^NmMG)0iou zi+A?|zsN`Y;6F{vO}W{3;57*Ww-%S8i{ZzOaK4a$lHxfWEkwRoyMLM1`ek`2ZjC{A zvN-f8)c`{;SK>zW$nR@pEwgz`s3OSY)9bdpr&<4tqZDbnA-6aL^sEtQplCDIk3;0s=4C zSZ!%Be>8dw->q-2iUW0s=WSIC)nGV-NZIE$iXud120g7GJyK8n?&JPHXRbY~8s-vz z3+}%p6wnG`w%I?P>=`{uExEOr$XyU!Fy0Hq(=quGX3a*J|FzFbTVy(MH{MLILsLY2 zAa{&!F?Y07%Iouf{w@n5wqfT89~yAFck4ae3Q;o#ypX~}wL-adz+({02ZUyt`{vt6~~LQ6sfJb|+Ap4Jx3b)0?@``W9(A4h%AknA+m4TvJ@d6JMrj=!H{KyB4lYol(CCs$yl-*OAoS>wMcd; z@=ovjFTB@vu5*4p=f3aj+@H@m_vfz9Yc|Gbo9tYDNzd*ERxWShzDYjGrzN&;m^1Ip z9@P)QcQbdi@!d)O^3P_B1?VT6ZmMSh)E~#OL$8^xduQYc?~OIQ`Fkb(%p< z)FXMnc=dddZD%ix=jBXF=iVB+fH4}ZoHm@VZLm=)URkHeRazxApF&k@=Yp&2`capl zJq*!Gu@@NB#zQjhxBm>JWl`$t5TUp}w8#)N#?qq0`K0g*Z?V>Xq9PQJdUthN}xe#%^jYy6N5K@^*a zf13LBH#zJb-5IqubNR9#`^CG$d`WKh>>P8SZ+y zGF_OG;hkX@U-b=rFEiiC7-w@mj`{msUwTWL%xUEG_nn9U?jJ|>*8!=#Yiw{ZFh|U7 zZ(f{@^d@TK#&42?G>5tV8ZHUJ@P<+!m~YBHD_IQ{gcAO(@8tu#Az@J2>|TOZUpE)# z0)H)jOzM?G3`h~;k^ZkDFZk8i!Nv;N+NmnN*}3!`Ce{(XlJRLsLW%Xo9v>Y+7OAb^ zgxebXY!45DF8#7Kem4v$b90c;_cm^TE4-1ue#XJm#n>SO%RR|C`I^n>z+WwizJ&Q6 zYDVHxX8IZ%c7M_=rj{cd>Cw2mxp6CMwBrQFxEjXHWDhp1G_sc$D<$6NS7va(VZO;K zQ$AF+N>jb;dd(AP1$bRb`Jy`sx7w+(Njy50R9D%Q9ty@8o@$20;h9)irTN5_N&N|) znV%Yjd>bbn{H&V2;odb187WnRhG4M`(c2X{MK+wm&r9mmmi!I3>zrbpE_C+2RsUX0 z9$J>tGT5|ygY0qGo4hmN{b=%KO5>8c@Y7*tqsSVzMfJy58lI^5_!drmsml>qkI;R; z|KHSyRvVqYS`sop&k%_+o#tb&?QOngM5RvygtoH+UfvT{ZMv-BD20Q1a&`jiD>Kvf zjZ6|Bqawbe!xI=nAt)sZL{glgtBn<0XiyXl7C8@7l4k%-BrtbAV^y4%#A)horoIq5 zH>PI;Cg`A}0VFWAt%!jHq&Gr-Y&kMPEUg>{ON)^VNN42=07izvU~wQydQh!mcz&)h z`m0iPi>wgVBs|A9K=Fti!fhgSL*rz)V?TKm@=<0(5ycKd10JxuQKWy4;f!WT(~1)9 znu`{+Gc12E;hLsYW@a{a4Keu=Ng$4ZrvOY#l119B;&BrY{JG%JOoMUTdky=S1(YM& z*PJw<8hpv{b#v}X>R@_>al@|#CTh)2*?*A=_b9j>puWS%x5SROG{GPRM@)`^kzr2X zZlztAG&S+BF{!sKXMR*NnVM1=7z-f^Ub(?uN2?@MR>dMSC**5jH6l0MB*Z1SZWN7P z5)nO5L7x*zl;L;Lv&uxUr0QE)tK;!lCI}v@&4DyWa+vkn+SHiSvc%84mU)4emO*gH z$RH4Oc#0^M7+e8iEdd6?sEOFfXeoe_27pwV?(IcA7z)$1UX~YlstnaEq3jBRMvfQrDbyL{vA;O|7sRvqy@88NY)8)r+6HVnUi*oRBMU6cBdIv*6h! zS?zcgJW?`L;Rxp3d5tzM#y(Y6w1>TZ32o@BwN#Mc?YPvrEYdhP=ErB`^^; z&Vi^jgnWF5EXz5pF`37rR~pvAc_R|@B)N@ms>pzgqMDcpd7^XHEwf{;@9^MzyuPm1 zank9;g=4Qj_KQA=#Q=Vx_0bg|YD31np_B*Hr>Tuwg?d(}e4Q6ez)7ytjD{SqzN%e+ z+&%ggAfLjj*V2{IF zf0V&0i0NLcpS)HMpcO0Lk``KbvZ6}y4U-fwd)3PR6+;*cAyXM=huqyi|8ZN+p{~8wLc>HfH|>i9p~F!B3>AL-QaHRQt0d|VSP2u6|W6p>ITK3rQ)EE zhvjj)cus9Mrc@Gjr7-xbfA<^L7X`_=?ItsS=skkk&iloos&DSaQG&DLT zOI{z1Zj+@%pWx#tM|eGAJiCI3+gEUhQeL)X?7UcU8@L z+#q=60Mf6 zT1pdtf`IhqRHv9bcEk|OC0=YaqEfO+h(IN8SC}!Jv^?)1IRtl&xL-OR;ZJVN2nlv~ zzh;s<$hIZG`MZ`*$v(dgDarre%yM@`=x__0TA&BK^hlV5>WJmQ(>DCAK)jz{^hRNHj_HWX4zN^0(Ci^qt_IOHLwE!ZgPy?GEn{)>N(5xCD0KrXJxI}6F zM)}xiL88)b@o0I7=Y+uR2R^wICq0fc5u5kk%RQ^J&%5j8ux7l{{M`=4droTKmPtaPfGI|6j`F z6T!vd*UKki^>*Q*5fkKDQ-Zp1Skl03k&wpH{$=K=!Tm>vANw5{dE zFGXJL^NRGI5L4#?s*dXD*e1gs7*ea5LTPED*hbKWDKVj&Bg}xlGJ9Hx3r-bL~Gy) z)(cjuf?Po7%>I)vF<0B>e(^+1PqEpklwSNDo4a_CF18wPc^Bt2S07$Y8%W+h + + + + TodoApp.Avalonia.Browser + + + + + + +
+
+

+ Powered by + + + + + + + + + + + + + + +

+
+
+ + + + diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Browser/wwwroot/main.js b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Browser/wwwroot/main.js new file mode 100644 index 00000000..bf1555e4 --- /dev/null +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Browser/wwwroot/main.js @@ -0,0 +1,13 @@ +import { dotnet } from './_framework/dotnet.js' + +const is_browser = typeof window != "undefined"; +if (!is_browser) throw new Error(`Expected to be running in a browser`); + +const dotnetRuntime = await dotnet + .withDiagnosticTracing(false) + .withApplicationArgumentsFromQuery() + .create(); + +const config = dotnetRuntime.getConfig(); + +await dotnetRuntime.runMain(config.mainAssemblyName, [globalThis.location.href]); diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Desktop/Program.cs b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Desktop/Program.cs new file mode 100644 index 00000000..49d2ca0d --- /dev/null +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Desktop/Program.cs @@ -0,0 +1,21 @@ +using System; +using Avalonia; + +namespace TodoApp.Avalonia.Desktop; + +sealed class Program +{ + // Initialization code. Don't use any Avalonia, third-party APIs or any + // SynchronizationContext-reliant code before AppMain is called: things aren't initialized + // yet and stuff might break. + [STAThread] + public static void Main(string[] args) => BuildAvaloniaApp() + .StartWithClassicDesktopLifetime(args); + + // Avalonia configuration, don't remove; also used by visual designer. + public static AppBuilder BuildAvaloniaApp() + => AppBuilder.Configure() + .UsePlatformDetect() + .WithInterFont() + .LogToTrace(); +} \ No newline at end of file diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Desktop/TodoApp.Avalonia.Desktop.csproj b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Desktop/TodoApp.Avalonia.Desktop.csproj new file mode 100644 index 00000000..361d6bce --- /dev/null +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Desktop/TodoApp.Avalonia.Desktop.csproj @@ -0,0 +1,24 @@ + + + WinExe + + net8.0 + enable + true + + + + app.manifest + + + + + + + + + + + + diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Desktop/app.manifest b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Desktop/app.manifest new file mode 100644 index 00000000..c387cccf --- /dev/null +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.Desktop/app.manifest @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.iOS/AppDelegate.cs b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.iOS/AppDelegate.cs new file mode 100644 index 00000000..3d656678 --- /dev/null +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.iOS/AppDelegate.cs @@ -0,0 +1,23 @@ +using Foundation; +using UIKit; +using Avalonia; +using Avalonia.Controls; +using Avalonia.iOS; +using Avalonia.Media; + +namespace TodoApp.Avalonia.iOS; + +// The UIApplicationDelegate for the application. This class is responsible for launching the +// User Interface of the application, as well as listening (and optionally responding) to +// application events from iOS. +[Register("AppDelegate")] +#pragma warning disable CA1711 // Identifiers should not have incorrect suffix +public partial class AppDelegate : AvaloniaAppDelegate +#pragma warning restore CA1711 // Identifiers should not have incorrect suffix +{ + protected override AppBuilder CustomizeAppBuilder(AppBuilder builder) + { + return base.CustomizeAppBuilder(builder) + .WithInterFont(); + } +} \ No newline at end of file diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.iOS/Entitlements.plist b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.iOS/Entitlements.plist new file mode 100644 index 00000000..0c67376e --- /dev/null +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.iOS/Entitlements.plist @@ -0,0 +1,5 @@ + + + + + diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.iOS/Info.plist b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.iOS/Info.plist new file mode 100644 index 00000000..8446c28e --- /dev/null +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.iOS/Info.plist @@ -0,0 +1,43 @@ + + + + + CFBundleDisplayName + TodoApp.Avalonia + CFBundleIdentifier + companyName.TodoApp.Avalonia + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1.0 + LSRequiresIPhoneOS + + MinimumOSVersion + 13.0 + UIDeviceFamily + + 1 + 2 + + UILaunchStoryboardName + LaunchScreen + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.iOS/Main.cs b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.iOS/Main.cs new file mode 100644 index 00000000..2395e797 --- /dev/null +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.iOS/Main.cs @@ -0,0 +1,14 @@ +using UIKit; + +namespace TodoApp.Avalonia.iOS; + +public class Application +{ + // This is the main entry point of the application. + static void Main(string[] args) + { + // if you want to use a different Application Delegate class from "AppDelegate" + // you can specify it here. + UIApplication.Main(args, null, typeof(AppDelegate)); + } +} \ No newline at end of file diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.iOS/Resources/LaunchScreen.xib b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.iOS/Resources/LaunchScreen.xib new file mode 100644 index 00000000..fb678d64 --- /dev/null +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.iOS/Resources/LaunchScreen.xib @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.iOS/TodoApp.Avalonia.iOS.csproj b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.iOS/TodoApp.Avalonia.iOS.csproj new file mode 100644 index 00000000..abf3b43c --- /dev/null +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.iOS/TodoApp.Avalonia.iOS.csproj @@ -0,0 +1,16 @@ + + + Exe + net8.0-ios + 13.0 + enable + + + + + + + + + + diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.sln b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.sln new file mode 100644 index 00000000..7499ac80 --- /dev/null +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia.sln @@ -0,0 +1,54 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.3.32811.315 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TodoApp.Avalonia", "TodoApp.Avalonia\TodoApp.Avalonia.csproj", "{EBFA8512-1EA5-4D8C-B4AC-AB5B48A6D568}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TodoApp.Avalonia.Desktop", "TodoApp.Avalonia.Desktop\TodoApp.Avalonia.Desktop.csproj", "{ABC31E74-02FF-46EB-B3B2-4E6AE43B456C}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TodoApp.Avalonia.Browser", "TodoApp.Avalonia.Browser\TodoApp.Avalonia.Browser.csproj", "{1C1A049E-235C-4CD0-B6FA-D53AC418F4DA}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TodoApp.Avalonia.iOS", "TodoApp.Avalonia.iOS\TodoApp.Avalonia.iOS.csproj", "{EBD9022F-BC83-4846-9A11-6F7F3772DC64}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TodoApp.Avalonia.Android", "TodoApp.Avalonia.Android\TodoApp.Avalonia.Android.csproj", "{7AD1DAC8-7FBE-49D5-8614-7321233DB82E}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{3DA99C4E-89E3-4049-9C22-0A7EC60D83D8}" + ProjectSection(SolutionItems) = preProject + Directory.Build.props = Directory.Build.props + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {EBFA8512-1EA5-4D8C-B4AC-AB5B48A6D568}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EBFA8512-1EA5-4D8C-B4AC-AB5B48A6D568}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EBFA8512-1EA5-4D8C-B4AC-AB5B48A6D568}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EBFA8512-1EA5-4D8C-B4AC-AB5B48A6D568}.Release|Any CPU.Build.0 = Release|Any CPU + {ABC31E74-02FF-46EB-B3B2-4E6AE43B456C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ABC31E74-02FF-46EB-B3B2-4E6AE43B456C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ABC31E74-02FF-46EB-B3B2-4E6AE43B456C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ABC31E74-02FF-46EB-B3B2-4E6AE43B456C}.Release|Any CPU.Build.0 = Release|Any CPU + {1C1A049E-235C-4CD0-B6FA-D53AC418F4DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1C1A049E-235C-4CD0-B6FA-D53AC418F4DA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1C1A049E-235C-4CD0-B6FA-D53AC418F4DA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1C1A049E-235C-4CD0-B6FA-D53AC418F4DA}.Release|Any CPU.Build.0 = Release|Any CPU + {EBD9022F-BC83-4846-9A11-6F7F3772DC64}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EBD9022F-BC83-4846-9A11-6F7F3772DC64}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EBD9022F-BC83-4846-9A11-6F7F3772DC64}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EBD9022F-BC83-4846-9A11-6F7F3772DC64}.Release|Any CPU.Build.0 = Release|Any CPU + {7AD1DAC8-7FBE-49D5-8614-7321233DB82E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7AD1DAC8-7FBE-49D5-8614-7321233DB82E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7AD1DAC8-7FBE-49D5-8614-7321233DB82E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7AD1DAC8-7FBE-49D5-8614-7321233DB82E}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {83CB65B8-011F-4ED7-BCD3-A6CFA935EF7E} + EndGlobalSection +EndGlobal diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/App.axaml b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/App.axaml new file mode 100644 index 00000000..8ade734a --- /dev/null +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/App.axaml @@ -0,0 +1,10 @@ + + + + + + + \ No newline at end of file diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/App.axaml.cs b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/App.axaml.cs new file mode 100644 index 00000000..344a4f0c --- /dev/null +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/App.axaml.cs @@ -0,0 +1,107 @@ +using System; +using Avalonia; +using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.Data.Core; +using Avalonia.Data.Core.Plugins; +using Avalonia.Markup.Xaml; +using Avalonia.Threading; +using Microsoft.Data.Sqlite; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using TodoApp.Avalonia.Database; +using TodoApp.Avalonia.Services; +using TodoApp.Avalonia.ViewModels; +using TodoApp.Avalonia.Views; + +namespace TodoApp.Avalonia; + +public partial class App : Application +{ + private readonly SqliteConnection dbConnection; + public IServiceProvider Services { get; } + + public App() + { + this.dbConnection = new SqliteConnection("Data Source=:memory:"); + this.dbConnection.Open(); + + // Create the IoC Services provider. + Services = new ServiceCollection() + .AddSingleton() + .AddScoped() + .AddDbContext(options => options.UseSqlite(this.dbConnection)) + .BuildServiceProvider(); + } + + public override void Initialize() + { + AvaloniaXamlLoader.Load(this); + } + + public override void OnFrameworkInitializationCompleted() + { + + if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + { + // Line below is needed to remove Avalonia data validation. + // Without this line you will get duplicate validations from both Avalonia and CT + BindingPlugins.DataValidators.RemoveAt(0); + desktop.MainWindow = new MainWindow { DataContext = GetRequiredService() }; + } + else if (ApplicationLifetime is ISingleViewApplicationLifetime singleViewPlatform) + { + singleViewPlatform.MainView = new MainView { DataContext = GetRequiredService() }; + } + + + // Initialize the database after DataContext was set + InitializeDatabase(); + + base.OnFrameworkInitializationCompleted(); + } + + private void InitializeDatabase() + { + using IServiceScope scope = Services.CreateScope(); + IDbInitializer initializer = scope.ServiceProvider.GetRequiredService(); + initializer.Initialize(); + + Dispatcher.UIThread.Post( + () => GetRequiredService().ShowInfoAlert("All data loaded"), + DispatcherPriority.Loaded); + } + + /// + /// A helper method for getting a service from the services collection. + /// + /// + /// You can see this in action in the class. + /// + /// The type of the service. + /// An instance of the service + public static TService GetRequiredService() where TService : notnull + => ((App)App.Current!).Services.GetRequiredService(); + + #region IDisposable + private bool hasDisposed; + + protected virtual void Dispose(bool disposing) + { + if (!this.hasDisposed) + { + if (disposing) + { + this.dbConnection.Close(); + } + + this.hasDisposed = true; + } + } + + public void Dispose() + { + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + #endregion +} \ No newline at end of file diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Assets/avalonia-logo.ico b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Assets/avalonia-logo.ico new file mode 100644 index 0000000000000000000000000000000000000000..da8d49ff9b94e52778f5324a1b87dd443a698b57 GIT binary patch literal 176111 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 zds⪻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

r@R8DskCg$QY%d=x6zD zS7xPZcT!SYuTEDHH==$j{oi%tH1uNt18`7s86HDF4!ZI235u(usyz~^-r(5>KU(d7 z)a7ngv1_-XG%RViwqV*k_ml3iUGtuJ5c2RwH;@=B(7% zUIHUb*azeIr0`R;S`mYr)%2}i+cA&*L|d`>V#ZKIl!GrxsGR!BgE{WX zikccGd2s0p#jEWTh=&EuV+qUM^#~>9eKCd3zORO>t0jqd+kxzl7y30*WYckjFsi}@ zdW7Z-3F;7%bVH>G@CTK-+y-C<7FFqR1ym24xsuezPkJ9-PO8rY;{R#PxcwjUYX=bo z#DLedtyomk;j2Z;>FT^09F~$h_^qQwKs+q8nT=$-vM%K^AwS;#>K*_!zjDy8{EJwe zkbWF+0fMP?A0K@5^p6ImaGGZCloL4E3LbrEKAJe(!U{Ic#~XMHjCmQ!JuUD5$)wy;NV}4N3gCcye(-{fFZ$Y=dT|JX15@@6ru1z1OCt^60t zw4Ve4g##Eb<0@Pc`TfQ?B6Pf6xv_Q=53-veSLQPJ5W*Qc%bXarrzz5ca!wS`=~n#< zLUP7yKzY_xf3 zlzw3`I#6;16WNqvCQ($3TwPCPso-ozcEMn&Uk9$$3=C+n&zqkDLwA~~0dNCF!?Jh? z45xtUg*6>C=$E3&%>3U;zq;w2AF2qTl#}ORej6JkW}yvJvXBJ`Yk zV+`ih|265EX7F`ol|x901({tr$zt$oKiH2dHAS(^7E&(p4COZ<){(V4YoJJ1OZNNK~zrXR&ID*fMF5ECciW9q5w-RhK)J*7V`8yvzm z)HiQ4-41XsP1A?Qac`;5A9II_Zs(*1!FPzZ_iJ2TWCU0QeItJ5#&Y?|Kg81%>)2g zXOVu(>(iM-K~oP~6Q`!6=t`rigOh2R2ul=Sc&M(+&}~Uqyq@GXh!cK#wvHl|siF#@{t(J`3#jPn z_MRgvnrg!^CGe(=56{s^|Ad8ZzgKoUu8InX6yxSoE^WNmK_%R2Lb#Ai#Hf46H(f`^ zYl}47_Bixq1TAW4y1oC%YCjEY^~KY%zeDH>)+>q{~n>G_wQCLnp&oVqhoCFU_X^6P$P0z~F3|<^%e8 zyA%8@oYrw{DHF<1_{S!F@5`0(>1B(f7x#L9f1L1*<@(X&z>>APke>VT`~3jv)-nT^ z!v9A39U8DB#{+VJC>MtZ88=2-Z`xY_FJ%Tx`8+)~PxU9wrC@fxEc}rt;G5Wb!EBuc zzR)8}%Q_ROKMF>9-v$jRo)7;>nWH=c0P@+HY8wQYYW+nr$yl1eZw+t5RMlkh^=cP) zK4q-8)#3^29$wd*Vv4PYw{+qKx<9}<4eQVl|L=@Ip6S7Og#l12A`z7>Gb#TO$F{}) zB@)3mOT}a_N|;Q#EbP+Kz^r#D)sRuWO@1tps@J^ zaK9f3JjS2;*De#TBY>&Gzd)3(XaQKQMe>POOkLT_L#oudq_E@>)g>eg)qAwF2>Dq3 z(qEl=;ljDCgKe*#@U^brk^HGBm}`LvR_SYa?mhy2>{Zz+Bq(aQEQGn<;{)0s_7m;g7Ta6$pHPzX!K*ER-yQvYT+C9LH?1j}3Q9Bdd;WoH=K0Gg9 z5)Nu$;U#{}31Wm_H!@?uUI1D&_@fgcKRPlxas3!^d~C$JDSBmH&_2DH+`9r_e&@_C zg8qBdVmGDX{lMV!mf-Ew_;<|8xoW(%vHz1o&hi{^g0S}S8McKwO0d2WBWeB|+ejY0 zrAl5emzq5bV`}%l--dQ7?}6maIi#rkyd(=hZr;;s-WC(-ouieFA{1y|Zd zKe+QrZhh1ZP<>N&heUl_|I`BPqB~Xb(L@9_YgA7)eyS_3%!LAiqS7Jn2UuWY%o^w; z3uUymR1=x`tpA$Xdz^I-tw=54+N@Y{d4jOo(9iP`6mkaNO5UW6}ySjXU$ET!J#4hrxX3u zZOPCWwBD`mhkH5KzwMh_jXERBbGIbdN=|u@*B;8^LPlmM>@T zAGftuKe@7yc1)2)1Vw>aiO8?N)ZgxBakpL`PDt0yPg}8~QiK%=@$~L7IKCG#gFC~& zr&gfs!jcOoarE@u$b~mOqvPO7sMg65(CBDcI9*sfs@sb1vfbnlzUgvjYs_WfRu4wJ zT;T|G+T#X1ZaCXmVBW_)4FftP4%d&900l<%%nlC1}dxMVXa*#$xa2TFyY zZxB&ZLc6-WY$cBHh^!3pI9!$sOB+J+f4feF*;`n2sx}FqMKCY?_@p*=pnLeR`d7Cl zOJmJjD>v$*MgSAe19g43~wD7Qo_Po-D&( zT1^}7r@p)aH^(dkP-}t6H-V=r$R~sw=*rUMWHZ@)VJyN(bKmYTz?BL12jJ=XWoJ1s zjx2NP0ze!dT0+M<;?z5JjA2gipXMntMHm5M12WJxdS6>K(?B?>+j-%Lye|{Xp}@1O+q!jjaMC2%4Na3>Kd&@7BNWyM^XDQ&^|w zRcxFfg;35V@S0NOo_-6yz-yfdNk=Je+Xf`)YClmyzfBSvYddfQM_k}} zDJD#`vzh+Nt(k6j<+(8QB1Wx`xF;R4;8aWNvY%Qo3PaL!*O-lwa)vRQZ>AlMNeS1m zb}V4N%^!*$TN?nG)f2#Q$Hske4u04}r7 z-9qbS>TZF%u?uz=9%Pp+HV-#>2h?H#kRmY+g)y?J))Ih@AKEdkQ+Z$LqK z`7ANpeSgupv|mCgLx6Lgh;Iqz84)S)2kR3h>=g{=fKVK z^oD~7j%X#;&fD_I(M7eNq3MyCe&gu@$SjH15}WI*J*T-I*X=U_y~5?MqmCcA6SwXt zrf+0&>%-#H3tXHz9C@923p@;wfW`stQuOo3RW-B;#-iZn1iRMo5%22z^J!M=IbS~G z*+N5W?;06@sa%HXhRClHATg3h<8xU2b3fPHJTSVL8bjMQREWBpZ1>k+_}F&*mLy8z zC3oYir@i)t(ArJfO#8Xrxm-(;(?rwmW`XTE3;Gi*ds&USQaU z$>EKED&D=56^5lMlZe^~p@oIkeuBpU%HI>k5HFcX1!`i&|>nXa2 zqi_(e2kPc}4LR}=emDna>C?0py!OOGcuj1Mc8fF0`xQ5KE^rFRm0m6=rfPI~kNS6y zjzDomiz6x^jYo*}xd*2E8J^}VeUz$=%)4TKfwg`E9>89p$E=8G#yEQ%x zv(3g+D2J8-gi9tbB;FcES-_9@_ zw*7b^sN^LfYnZSb|BdzjP@TT6y}0x4K$kmrhGiU6dqG2}E!TbDda8?=v5$6J9J&o& zR7gTSDM6)eO&Jz(mXAk1;Y;>qmjpXoz@&qNyf{3B@J3-9Q!H5Qko;AREokJVSWft+UWDgh`@n0hXO1L&kM6*5wHjg(mpJJ4kpr}$+o%u0^*7jZquq00B za-H4ZAU|2H3?ys4YbqMAbl=i3wbhwbKd}&Qnq@MM(SYKm$)4)frEHuikRt}xv5!ln z1^2#moe1?hc^7xv5!q_d%VD<4NIU17>LpC>G``cR9vS+w60$ZaM_T6o1K%`e=FRSK z13<3@60S(_ST*$z2qRcQLBUYljoPO1pA&-3R?&R8F!fl_DhUkGQp3Sf`kJ=M6O+hS zr^H<=x>{jl_yc&R$WCL5dpzGc^@j#ntn%g-9j{ON2W4d5Y8weG(l2>6w zVvljr%~JS~#DaW8dSB5{qkK5PF@UGH7%2k?RWb@8Y3)5z6w036yr%ZQ? z6VEh;6AuC{_q2ys>ja`!_f|Jb8MXk=d}o@ly8(zJMSvH@EP*STWfm9Wqg9>6T}7k{ zonsEg7K3L3&t;gexOT-a&1Em%y(fqM8qkYpdK8MDO|~0~{vKXQfo~%ZHQy8UVTU9L zQ~W=<{$8$Kgj$5h;uk+T1`(UWLKAdoV?1p4x2{s{F|!u$@|Xk#AH{Z1DJGj7z{S-S z4?u;YkEPCS{1u=~(cBU>@@n;+?F3?*GNn`P`ZbrA=VGr2XSc%C9-LfUc*}z!qp%QY zM1(#H#QS~y=8>7!{)Z^Gv60&oiJZrcZ2*s-Sq1%c6lFV)doeBBtynu#Mv7w0vSBd} z+Ja^M`nVHKuP*hy+nOJHX3h^=XuGgOhHi_kDz3Y4F(%jps;Na>VLV*C_!Zzxi&&Ea zP25;-h$%87eEGnxE7c$&d!g0^7yywh7c`MB4&hQZfC#XNr>=RUY(Ps}skoY4VMdvX z0EI0DQ>r*io0>QoV{z{qZxM0fS>WOb2jb~SJF?90FRmCoL#Sn_l>_7?J=IS8G7Vf% zTLu;+AAKc^g`6b5Jn;aGKBBl@q&&N23gL`yd<@aZGc`xb3-b*$>i}L>6gniT7`zA> z1l}5=x!*_g?cJ|AKe~7UF!zJsTUy-ZL&r~5DmzEd4_2jP4dY4U#ov#a^?5s$=S$0x z(h&kLz?#4|FwX`L4?#YJun{U#;N!XQM>J@LyxCzT+V=!mlfmMv$L)UY6PLF4do~BJ9%**9~)K)>Hpc zsG~+C_-FB9DGCl^c5Gt?l0hD})O-vJ4aZ%zoM+@`Egm!#{%5~Cmmq?f$(TRkf4>v^ zkYD8ep{==sGm2qrzV#9lN%;y5&rpRviz$Mc_T_0PJ@+g~1QnP8D&iS%i>05oEvYae?M=0O)SixB@F`Cxk(}5g^n(kG6yM!aTbf?tTy5a z^}&ofBB&HK0w`7|+I7dn4NgKV6eEIbV~ydE%S;qw_G=GZ`>mC|MF{^2sgaAP#vt_f zB5xm|1sFnQZy|xSpPIR_twS+u+(wV6!R(gd)X2yqxNdaJl0ubr;oL4XgSuG3K2Kk2}zg$3pBm0nbrA>kQa9Rtp25 z1?plVbR)pQzxBhj4dYt9b$ndl;XnKZB70|UgAHPf0al8d@N||sFa1u8F1m=Zzc?RV z(wP}meSn^yD14#^*8?Sh7x7PW(=!mmHefS&;RkVh2Egw^CjpZhi=OTtKjMs|(Urkx z5P9;_#fDj<&FSLQ4d|0&O;ZySNhVZLNS0?_s!eJx<<(2@*$41!dA2Va1N&Uq>_zb4 z1mK+z%0h#F-k|Q`g$}2X6=uh&i^A38VVU7=D=_{dC)4}^1t%4dN%(UOp?msX95fF- zZIdG`VYE+!7l>|1c6R;Uik&&rT6-bRzsjTJuv*~d%Ans2@ow;s>75?sCrD zbG#aGpj<{`;`4|{wOx-y#oH!inSHBPS`92|A|S1xTCb&`<167IcU8m{6ICWQRWCGt zdXa=~`)7RrIHY!El0z6G^-Urv+MZCKi<XQyxy;~L4HY`fKKf`{%0JIWGKJc1me+av z%_fHkr&&-UvG)Jtt?db$zdSYKCgbgix67!@y`l1#l}+?mq}+`Pbsyt_A4f#vq7C;I zT>CUNT8<(HPcrfo&(xh3b^CclqMnXlztCF_d^lz3fu@O-fCB`2CIc9!F9oDS)*$;tk%3)kM4D?{1NTI0<{B&=6 zs1LsE{Eau<)`%Mi7G~pd_xbd>`aE=FI$EU~K;=Xb|w7Y+5 zN2J>P$XOHV`FBuQ<}$4EE}5MlNDKX{Vdzkb~V4Bkbu4IBikP{WO@k(K^Tq=uu+ zsa5=Gfppw)y_4E_b@of?wj&R!dy~D(NZHVn)V`N`iNGut*WAszZzxG!g=jmNmgQ5i zNlH5VaM|w|E9(e1JJ<&_eTOEm`abc66RL2TcK-@;d9_C9W!In^8U+f)&N>o{tEBWm=2QawvC)baxT7rE4K; zo#{waCXei`9T(TV4dknZ;XvUpAbfH*G;TbLNu+k<+};{WF~JY}qR#%dbkwOM_H;p! zd&>e9xGE9gIa}Haf$C7z#~M<>*!M^$8`rVcr%0`Rn@z>Q7+Q;JmgCV+MtWV6nN

!LxQh!NmF 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 options) : DbContext(options) +{ + public DbSet TodoItems => Set(); + + //protected override void OnDatasyncInitialization(DatasyncOfflineOptionsBuilder optionsBuilder) + //{ + // HttpClientOptions clientOptions = new() + // { + // Endpoint = new Uri("https://YOURSITEHERE.azurewebsites.net/"), + // HttpPipeline = [new LoggingHandler()] + // }; + // _ = optionsBuilder.UseHttpClientOptions(clientOptions); + //} + + public async Task SynchronizeAsync(CancellationToken cancellationToken = default) + { + //PushResult pushResult = await this.PushAsync(cancellationToken); + //if (!pushResult.IsSuccessful) + //{ + // throw new ApplicationException($"Push failed: {pushResult.FailedRequests.FirstOrDefault().Value.ReasonPhrase}"); + //} + + //PullResult pullResult = await this.PullAsync(cancellationToken); + //if (!pullResult.IsSuccessful) + //{ + // throw new ApplicationException($"Pull failed: {pullResult.FailedRequests.FirstOrDefault().Value.ReasonPhrase}"); + //} + } +} \ No newline at end of file diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/DbContextInitializer.cs b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/DbContextInitializer.cs new file mode 100644 index 00000000..ad37cf27 --- /dev/null +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/DbContextInitializer.cs @@ -0,0 +1,29 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.Infrastructure; + +namespace TodoApp.Avalonia.Database; + +/// +/// Use this class to initialize the database. In this sample, we just create +/// the database using . However, you +/// may want to use migrations. +/// +/// The context for the database. +public class DbContextInitializer(AppDbContext context) : IDbInitializer +{ + /// + public void Initialize() + { + _ = context.Database.EnsureCreated(); + // Task.Run(async () => await context.SynchronizeAsync()); + } + + /// + public Task InitializeAsync(CancellationToken cancellationToken = default) + => context.Database.EnsureCreatedAsync(cancellationToken); +} \ No newline at end of file diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/IDbInitializer.cs b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/IDbInitializer.cs new file mode 100644 index 00000000..d4492286 --- /dev/null +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/IDbInitializer.cs @@ -0,0 +1,26 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading; +using System.Threading.Tasks; + +namespace TodoApp.Avalonia.Database; + +/// +/// An interface to initialize a database. +/// +public interface IDbInitializer +{ + /// + /// Synchronously initialize the database. + /// + void Initialize(); + + /// + /// Asynchronously initialize the database. + /// + /// A to observe. + /// A task that resolves when complete. + Task InitializeAsync(CancellationToken cancellationToken = default); +} diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/OfflineClientEntry.cs b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/OfflineClientEntry.cs new file mode 100644 index 00000000..3d6373fb --- /dev/null +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/OfflineClientEntry.cs @@ -0,0 +1,20 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.ComponentModel.DataAnnotations; + +namespace TodoApp.Avalonia.Database; + +/// +/// An abstract class for working with offline entities. +/// +public abstract class OfflineClientEntity +{ + [Key] + public string Id { get; set; } = Guid.NewGuid().ToString("N"); + public DateTimeOffset? UpdatedAt { get; set; } + public string? Version { get; set; } + public bool Deleted { get; set; } +} \ No newline at end of file diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/ToDoItem.cs b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/ToDoItem.cs new file mode 100644 index 00000000..2724ec72 --- /dev/null +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/ToDoItem.cs @@ -0,0 +1,11 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace TodoApp.Avalonia.Database; + +public class TodoItem : OfflineClientEntity +{ + public string Title { get; set; } = string.Empty; + public bool IsComplete { get; set; } = false; +} diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Services/DialogManager.cs b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Services/DialogManager.cs new file mode 100644 index 00000000..18978f43 --- /dev/null +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Services/DialogManager.cs @@ -0,0 +1,108 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Avalonia; +using Avalonia.Controls; +using Avalonia.Controls.Notifications; +using Avalonia.Platform.Storage; +using TodoApp.Avalonia.Views; + +namespace TodoApp.Avalonia.Services; + + public class DialogManager + { + private static readonly Dictionary RegistrationMapper = + new Dictionary(); + + static DialogManager() + { + RegisterProperty.Changed.AddClassHandler(RegisterChanged); + } + + private static void RegisterChanged(Visual sender, AvaloniaPropertyChangedEventArgs e) + { + if (sender is null) + { + throw new InvalidOperationException("The DialogManager can only be registered on a Visual"); + } + + // Unregister any old registered context + if (e.OldValue != null) + { + RegistrationMapper.Remove(e.OldValue); + } + + // Register any new context + if (e.NewValue != null) + { + RegistrationMapper.Add(e.NewValue, sender); + } + } + + /// + /// This property handles the registration of Views and ViewModel + /// + public static readonly AttachedProperty RegisterProperty = AvaloniaProperty.RegisterAttached( + "Register"); + + /// + /// Accessor for Attached property . + /// + public static void SetRegister(AvaloniaObject element, object value) + { + element.SetValue(RegisterProperty, value); + } + + /// + /// Accessor for Attached property . + /// + public static object? GetRegister(AvaloniaObject element) + { + return element.GetValue(RegisterProperty); + } + + /// + /// Gets the associated for a given context. Returns null, if none was registered + /// + /// The context to lookup + /// The registered Visual for the context or null if none was found + public static Visual? GetVisualForContext(object context) + { + return RegistrationMapper.TryGetValue(context, out var result) ? result : null; + } + + /// + /// Gets the parent for the given context. Returns null, if no TopLevel was found + /// + /// The context to lookup + /// The registered TopLevel for the context or null if none was found + public static TopLevel? GetTopLevelForContext(object context) + { + return TopLevel.GetTopLevel(GetVisualForContext(context)); + } + } + + /// + /// A helper class to manage dialogs via extension methods. Add more on your own + /// + public static class DialogHelper + { + public static void ShowErrorAlert(this object context, string message) + { + MainView view = (MainView)DialogManager.GetVisualForContext(context)!; + + view.ControlNotifications.Show(message, NotificationType.Warning); + } + + public static void ShowInfoAlert(this object context, string message) + { + MainView view = (MainView)DialogManager.GetVisualForContext(context)!; + + view.ControlNotifications.Show(message, NotificationType.Information, TimeSpan.FromSeconds(3)); + } + } \ No newline at end of file diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/TodoApp.Avalonia.csproj b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/TodoApp.Avalonia.csproj new file mode 100644 index 00000000..22022179 --- /dev/null +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/TodoApp.Avalonia.csproj @@ -0,0 +1,25 @@ + + + net8.0 + enable + latest + true + + + + + + + + + + + + + + + + + + + diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoItemViewModel.cs b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoItemViewModel.cs new file mode 100644 index 00000000..a75df8b9 --- /dev/null +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoItemViewModel.cs @@ -0,0 +1,62 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using CommunityToolkit.Mvvm.ComponentModel; +using TodoApp.Avalonia.Database; + +namespace TodoApp.Avalonia.ViewModels; + +public partial class TodoItemViewModel : ViewModelBase +{ + /// + /// Creates a new blank ToDoItemViewModel + /// + public TodoItemViewModel() + { + // empty + } + + /// + /// Creates a new ToDoItemViewModel for the given + /// + /// The item to load + public TodoItemViewModel(TodoItem item) + { + // Init the properties with the given values + IsChecked = item.IsComplete; + Content = item.Title; + } + + /// + /// Gets or sets the checked status of each item + /// + // NOTE: This property is made without source generator. Uncomment the line below to use the source generator + // [ObservableProperty] + private bool _isChecked; + + public bool IsChecked + { + get { return _isChecked; } + set { SetProperty(ref _isChecked, value); } + } + + /// + /// Gets or sets the content of the to-do item + /// + [ObservableProperty] + private string? _content; + + /// + /// Gets a ToDoItem of this ViewModel + /// + /// The ToDoItem + public TodoItem GetToDoItem() + { + return new TodoItem() + { + IsComplete = this.IsChecked, + Title = this.Content + }; + } +} \ No newline at end of file diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoListViewModel.cs b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoListViewModel.cs new file mode 100644 index 00000000..de2bbddb --- /dev/null +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoListViewModel.cs @@ -0,0 +1,133 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using CommunityToolkit.Datasync.Client; +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using Microsoft.EntityFrameworkCore; +using TodoApp.Avalonia.Database; +using TodoApp.Avalonia.Services; + +namespace TodoApp.Avalonia.ViewModels; + +public partial class TodoListViewModel(AppDbContext context) : ViewModelBase +{ + [ObservableProperty] + private bool isRefreshing; + + [ObservableProperty] + private ConcurrentObservableCollection items = []; + + // -- Adding new Items -- + + /// + /// This command is used to add a new Item to the List + /// + [RelayCommand (CanExecute = nameof(CanAddItem))] + private async Task AddItemAsync(CancellationToken cancellationToken) + { + try + { + // Create the new item + TodoItem addition = new() + { + Id = Guid.NewGuid().ToString("N"), + Title = NewItemContent ?? throw new InvalidOperationException("New item content may not be null or empty") + }; + + // Add the item to the database + _ = context.TodoItems.Add(addition); + _ = await context.SaveChangesAsync(cancellationToken); + + // Add the item to the end of the list + Items.Add(new TodoItemViewModel(addition)); + + // Update the title field ready for next insertion. + NewItemContent = string.Empty; + } + catch (Exception ex) + { + this.ShowErrorAlert(ex.Message); + } + } + + /// + /// Gets or set the content for new Items to add. If this string is not empty, the AddItemCommand will be enabled automatically + /// + [ObservableProperty] + [NotifyCanExecuteChangedFor(nameof(AddItemCommand))] // This attribute will invalidate the command each time this property changes + private string? _newItemContent; + + /// + /// Returns if a new Item can be added. We require to have the NewItem some Text + /// + private bool CanAddItem() => !string.IsNullOrWhiteSpace(NewItemContent); + + // -- Removing Items -- + + /// + /// Removes the given Item from the list + /// + /// the item to remove + [RelayCommand] + private void RemoveItem(TodoItemViewModel item) + { + // Remove the given item from the list + Items.Remove(item); + } + + + [RelayCommand] + public async Task UpdateItemAsync(TodoItem item, CancellationToken cancellationToken = default) + { + try + { + TodoItem? storedItem = await context.TodoItems.FindAsync([item.Id], cancellationToken); + if (storedItem is not null) + { + storedItem.IsComplete = !storedItem.IsComplete; + + // Store the updated item in the database + _ = context.TodoItems.Update(storedItem); + _ = await context.SaveChangesAsync(cancellationToken); + + // WPF does not respect changes to the observable collection in other threads + // so we just refresh the items + List dbItems = await context.TodoItems.ToListAsync(cancellationToken); + Items.Clear(); + _ = Items.AddRange(dbItems.Select(x => new TodoItemViewModel(x))); + } + else + { + this.ShowErrorAlert("Item not found"); + } + } + catch (Exception ex) + { + this.ShowErrorAlert(ex.Message); + } + } + + [RelayCommand] + public async Task RefreshItemsAsync(CancellationToken cancellationToken = default) + { + try + { + // Synchronize with the remote service + await context.SynchronizeAsync(cancellationToken); + + // Retrieve the items from the service + List dbItems = await context.TodoItems.ToListAsync(cancellationToken); + + // Replace the items in the collection + Items.Clear(); + _ = Items.AddRange(dbItems.Select(x => new TodoItemViewModel(x))); + } + catch (Exception ex) + { + this.ShowErrorAlert(ex.Message); + } + } +} \ No newline at end of file diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/ViewModelBase.cs b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/ViewModelBase.cs new file mode 100644 index 00000000..c81cf45f --- /dev/null +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/ViewModelBase.cs @@ -0,0 +1,7 @@ +using CommunityToolkit.Mvvm.ComponentModel; + +namespace TodoApp.Avalonia.ViewModels; + +public abstract class ViewModelBase : ObservableObject +{ +} \ No newline at end of file diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Views/MainView.axaml b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Views/MainView.axaml new file mode 100644 index 00000000..07d0cf90 --- /dev/null +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Views/MainView.axaml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Views/MainView.axaml.cs b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Views/MainView.axaml.cs new file mode 100644 index 00000000..b753f613 --- /dev/null +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Views/MainView.axaml.cs @@ -0,0 +1,11 @@ +using Avalonia.Controls; + +namespace TodoApp.Avalonia.Views; + +public partial class MainView : UserControl +{ + public MainView() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Views/MainWindow.axaml b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Views/MainWindow.axaml new file mode 100644 index 00000000..8d0912a9 --- /dev/null +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Views/MainWindow.axaml @@ -0,0 +1,12 @@ + + + diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Views/MainWindow.axaml.cs b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Views/MainWindow.axaml.cs new file mode 100644 index 00000000..76f1487c --- /dev/null +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Views/MainWindow.axaml.cs @@ -0,0 +1,11 @@ +using Avalonia.Controls; + +namespace TodoApp.Avalonia.Views; + +public partial class MainWindow : Window +{ + public MainWindow() + { + InitializeComponent(); + } +} \ No newline at end of file From 6fd0b8f652dd12e97b9fb47aef7fc5f4ad995b63 Mon Sep 17 00:00:00 2001 From: timunie Date: Mon, 21 Oct 2024 00:01:52 +0200 Subject: [PATCH 02/13] WIP --- .../TodoApp.Avalonia/App.axaml | 35 +++++++++++-- .../ViewModels/TodoItemViewModel.cs | 50 ++++++++++++++----- .../ViewModels/TodoListViewModel.cs | 26 +++++----- 3 files changed, 83 insertions(+), 28 deletions(-) diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/App.axaml b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/App.axaml index 8ade734a..b6267126 100644 --- a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/App.axaml +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/App.axaml @@ -1,10 +1,39 @@ - - + RequestedThemeVariant="Light"> + + + + + M 16.500001 0 C 15.52778 0 14.688382 0.35533588 14.101563 0.87695315 C 13.514743 1.3985704 13.165432 2.0458273 12.939454 2.6484376 C 12.757473 3.1337185 12.652358 3.6048008 12.589844 4.0000001 L 3.0000001 4.0000001 A 1 1 0 0 0 2.0000001 5.0000002 A 1 1 0 0 0 3.0000001 6.0000002 L 4.0253908 6.0000002 A 1 1 0 0 0 4.0078126 6.1250002 L 7.1171877 31.000001 L 25.882813 31.000001 L 28.992188 6.1250002 A 1 1 0 0 0 28.996095 6.0000002 L 30.000001 6.0000002 A 1 1 0 0 0 31.000001 5.0000002 A 1 1 0 0 0 30.000001 4.0000001 L 20.410157 4.0000001 C 20.347644 3.6048008 20.24253 3.1337185 20.060548 2.6484376 C 19.834569 2.0458273 19.485258 1.3985704 18.898438 0.87695315 C 18.31162 0.35533585 17.472221 -7.4014797e-17 16.500001 0 z M 16.500001 2.0000001 C 17.027777 2.0000001 17.313384 2.1446656 17.570313 2.3730469 C 17.827243 2.6014283 18.040434 2.9541747 18.189454 3.3515626 C 18.271334 3.5699097 18.330561 3.7916862 18.375001 4.0000001 L 14.625 4.0000001 C 14.66944 3.7916862 14.728668 3.5699097 14.810547 3.3515626 C 14.959568 2.9541747 15.172758 2.6014283 15.429688 2.3730469 C 15.686617 2.1446655 15.972223 2.0000001 16.500001 2.0000001 z M 6.0078127 6.0000002 L 26.992188 6.0000002 L 24.117188 29.000001 L 8.8828128 29.000001 L 6.0078127 6.0000002 z M 16.500001 7.9199221 A 1 1 0 0 0 15.5 8.9199222 L 15.5 27.402345 A 1 1 0 0 0 16.500001 28.402345 A 1 1 0 0 0 17.500001 27.402345 L 17.500001 8.9199222 A 1 1 0 0 0 16.500001 7.9199221 z M 9.8886722 8.0058596 A 1 1 0 0 0 9.0058597 9.1113284 L 11.00586 27.111329 A 1 1 0 0 0 12.111329 27.994141 A 1 1 0 0 0 12.994141 26.888673 L 10.994141 8.8886722 A 1 1 0 0 0 9.8886722 8.0058596 z M 23.111329 8.0058596 A 1 1 0 0 0 22.00586 8.8886722 L 20.00586 26.888673 A 1 1 0 0 0 20.888673 27.994141 A 1 1 0 0 0 21.994141 27.111329 L 23.994141 9.1113284 A 1 1 0 0 0 23.111329 8.0058596 z + M 57.070314 2.7402345 C 48.797905 2.7402345 42.070314 9.4678252 42.070314 17.740235 C 42.070314 26.012646 48.797905 32.740235 57.070314 32.740235 C 65.342725 32.740235 72.070315 26.012646 72.070315 17.740235 C 72.070315 9.4678252 65.342725 2.7402345 57.070314 2.7402345 z M 57.070314 4.7402345 C 64.261847 4.7402345 70.070315 10.548703 70.070315 17.740235 C 70.070315 24.931768 64.261847 30.740235 57.070314 30.740235 C 49.878782 30.740235 44.070314 24.931768 44.070314 17.740235 C 44.070314 10.548703 49.878782 4.7402345 57.070314 4.7402345 z M 63.972658 10.779297 A 1 1 0 0 0 63.285158 11.115235 L 54.007814 21.621094 L 50.865236 17.949219 A 1 1 0 0 0 49.45508 17.837891 A 1 1 0 0 0 49.345705 19.248047 L 53.982424 24.669923 L 64.785158 12.439454 A 1 1 0 0 0 64.697268 11.029297 A 1 1 0 0 0 63.972658 10.779297 z + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoItemViewModel.cs b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoItemViewModel.cs index a75df8b9..324d7aba 100644 --- a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoItemViewModel.cs +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoItemViewModel.cs @@ -2,32 +2,42 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; +using System.Threading; +using System.Threading.Tasks; using CommunityToolkit.Mvvm.ComponentModel; using TodoApp.Avalonia.Database; +using TodoApp.Avalonia.Services; namespace TodoApp.Avalonia.ViewModels; public partial class TodoItemViewModel : ViewModelBase { + private TodoItem? _todoItem; + + private TodoListViewModel _Parent; + /// /// Creates a new blank ToDoItemViewModel /// - public TodoItemViewModel() + public TodoItemViewModel(TodoListViewModel _parent) { - // empty + this._Parent = _parent; } - + /// /// Creates a new ToDoItemViewModel for the given /// /// The item to load - public TodoItemViewModel(TodoItem item) + public TodoItemViewModel(TodoItem item, TodoListViewModel _parent) : this(_parent) { // Init the properties with the given values IsChecked = item.IsComplete; Content = item.Title; + + this._todoItem = item; } - + /// /// Gets or sets the checked status of each item /// @@ -38,25 +48,39 @@ public TodoItemViewModel(TodoItem item) public bool IsChecked { get { return _isChecked; } - set { SetProperty(ref _isChecked, value); } + set + { + if (SetProperty(ref this._isChecked, value)) + { + _ = UpdateIsCheckedAsync(); // TODO use Task instead here + } + } + } + + private async Task UpdateIsCheckedAsync() + { + await this._Parent.UpdateItemAsync(this); } + /// /// Gets or sets the content of the to-do item /// - [ObservableProperty] - private string? _content; - + [ObservableProperty] private string? _content; + /// /// Gets a ToDoItem of this ViewModel /// /// The ToDoItem public TodoItem GetToDoItem() { - return new TodoItem() + if (this._todoItem is not null) { - IsComplete = this.IsChecked, - Title = this.Content - }; + this._todoItem.Title = Content; + return this._todoItem; + } + + // if no todoItem model is found, return a new one + return new TodoItem() { IsComplete = this.IsChecked, Title = this.Content }; } } \ No newline at end of file diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoListViewModel.cs b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoListViewModel.cs index de2bbddb..61534942 100644 --- a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoListViewModel.cs +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoListViewModel.cs @@ -42,7 +42,7 @@ private async Task AddItemAsync(CancellationToken cancellationToken) _ = await context.SaveChangesAsync(cancellationToken); // Add the item to the end of the list - Items.Add(new TodoItemViewModel(addition)); + Items.Add(new TodoItemViewModel(addition, this)); // Update the title field ready for next insertion. NewItemContent = string.Empty; @@ -72,41 +72,43 @@ private async Task AddItemAsync(CancellationToken cancellationToken) /// /// the item to remove [RelayCommand] - private void RemoveItem(TodoItemViewModel item) + private async Task RemoveItemAsync(TodoItemViewModel item) { // Remove the given item from the list Items.Remove(item); + + _ = context.TodoItems.Remove(item.GetToDoItem()); + _ = await context.SaveChangesAsync(); } - [RelayCommand] - public async Task UpdateItemAsync(TodoItem item, CancellationToken cancellationToken = default) + public async Task UpdateItemAsync(TodoItemViewModel item, CancellationToken cancellationToken = default) { try { - TodoItem? storedItem = await context.TodoItems.FindAsync([item.Id], cancellationToken); + TodoItem? storedItem = await context.TodoItems.FindAsync([item.GetToDoItem().Id], cancellationToken); if (storedItem is not null) { - storedItem.IsComplete = !storedItem.IsComplete; + storedItem.IsComplete = item.IsChecked; // Store the updated item in the database _ = context.TodoItems.Update(storedItem); _ = await context.SaveChangesAsync(cancellationToken); + + item.IsChecked = storedItem.IsComplete; - // WPF does not respect changes to the observable collection in other threads - // so we just refresh the items - List dbItems = await context.TodoItems.ToListAsync(cancellationToken); - Items.Clear(); - _ = Items.AddRange(dbItems.Select(x => new TodoItemViewModel(x))); + return true; } else { this.ShowErrorAlert("Item not found"); + return false; } } catch (Exception ex) { this.ShowErrorAlert(ex.Message); + return false; } } @@ -123,7 +125,7 @@ public async Task RefreshItemsAsync(CancellationToken cancellationToken = defaul // Replace the items in the collection Items.Clear(); - _ = Items.AddRange(dbItems.Select(x => new TodoItemViewModel(x))); + _ = Items.AddRange(dbItems.Select(x => new TodoItemViewModel(x, this))); } catch (Exception ex) { From 1ab5ca8e0ee742224ee427e60a5e8688c0cf3e15 Mon Sep 17 00:00:00 2001 From: timunie Date: Sun, 27 Oct 2024 22:26:36 +0100 Subject: [PATCH 03/13] Implement asnyc IsCheckedChanged support --- .../ViewModels/TodoItemViewModel.cs | 61 ++++++++++++------- .../ViewModels/TodoListViewModel.cs | 34 +---------- 2 files changed, 42 insertions(+), 53 deletions(-) diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoItemViewModel.cs b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoItemViewModel.cs index 324d7aba..ae890ab3 100644 --- a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoItemViewModel.cs +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoItemViewModel.cs @@ -11,29 +11,21 @@ namespace TodoApp.Avalonia.ViewModels; -public partial class TodoItemViewModel : ViewModelBase +public partial class TodoItemViewModel(TodoListViewModel parent, AppDbContext context) : ViewModelBase { private TodoItem? _todoItem; - private TodoListViewModel _Parent; - - /// - /// Creates a new blank ToDoItemViewModel - /// - public TodoItemViewModel(TodoListViewModel _parent) - { - this._Parent = _parent; - } - /// - /// Creates a new ToDoItemViewModel for the given + /// Creates a new ToDoItemViewModel for the given /// /// The item to load - public TodoItemViewModel(TodoItem item, TodoListViewModel _parent) : this(_parent) + /// The which is the parent + /// The to use + public TodoItemViewModel(TodoItem item, TodoListViewModel parent, AppDbContext context) : this(parent, context) { // Init the properties with the given values - IsChecked = item.IsComplete; - Content = item.Title; + this._isChecked = item.IsComplete; + this._content = item.Title; this._todoItem = item; } @@ -50,16 +42,43 @@ public bool IsChecked get { return _isChecked; } set { - if (SetProperty(ref this._isChecked, value)) - { - _ = UpdateIsCheckedAsync(); // TODO use Task instead here - } + UpdateIsChecked(value); } } - private async Task UpdateIsCheckedAsync() + private async void UpdateIsChecked(bool value) + { + await UpdateIsCheckedAsync(value); + } + + private async Task UpdateIsCheckedAsync(bool newValue, CancellationToken cancellationToken = default) { - await this._Parent.UpdateItemAsync(this); + try + { + TodoItem? storedItem = await context.TodoItems.FindAsync([GetToDoItem().Id], cancellationToken); + + if (storedItem is not null) + { + storedItem.IsComplete = newValue; + + // Store the updated item in the database + _ = context.TodoItems.Update(storedItem); + _ = await context.SaveChangesAsync(cancellationToken); + + parent.ShowInfoAlert("Saved changes successfully"); + SetProperty(ref this._isChecked, storedItem.IsComplete); + } + else + { + parent.ShowErrorAlert("Item not found"); + OnPropertyChanged(nameof(IsChecked)); // Notify the UI about the current value + } + } + catch (Exception ex) + { + parent.ShowErrorAlert(ex.Message); + OnPropertyChanged(nameof(IsChecked)); // Notify the UI about the current value + } } diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoListViewModel.cs b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoListViewModel.cs index 61534942..615d707f 100644 --- a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoListViewModel.cs +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoListViewModel.cs @@ -42,7 +42,7 @@ private async Task AddItemAsync(CancellationToken cancellationToken) _ = await context.SaveChangesAsync(cancellationToken); // Add the item to the end of the list - Items.Add(new TodoItemViewModel(addition, this)); + Items.Add(new TodoItemViewModel(addition, this, context)); // Update the title field ready for next insertion. NewItemContent = string.Empty; @@ -82,36 +82,6 @@ private async Task RemoveItemAsync(TodoItemViewModel item) } - public async Task UpdateItemAsync(TodoItemViewModel item, CancellationToken cancellationToken = default) - { - try - { - TodoItem? storedItem = await context.TodoItems.FindAsync([item.GetToDoItem().Id], cancellationToken); - if (storedItem is not null) - { - storedItem.IsComplete = item.IsChecked; - - // Store the updated item in the database - _ = context.TodoItems.Update(storedItem); - _ = await context.SaveChangesAsync(cancellationToken); - - item.IsChecked = storedItem.IsComplete; - - return true; - } - else - { - this.ShowErrorAlert("Item not found"); - return false; - } - } - catch (Exception ex) - { - this.ShowErrorAlert(ex.Message); - return false; - } - } - [RelayCommand] public async Task RefreshItemsAsync(CancellationToken cancellationToken = default) { @@ -125,7 +95,7 @@ public async Task RefreshItemsAsync(CancellationToken cancellationToken = defaul // Replace the items in the collection Items.Clear(); - _ = Items.AddRange(dbItems.Select(x => new TodoItemViewModel(x, this))); + _ = Items.AddRange(dbItems.Select(x => new TodoItemViewModel(x, this, context))); } catch (Exception ex) { From 2fbd706868d55dea2f8fa4ab66b57c7a2961dcd9 Mon Sep 17 00:00:00 2001 From: Tim <47110241+timunie@users.noreply.github.com> Date: Sun, 17 Nov 2024 17:56:40 +0100 Subject: [PATCH 04/13] fix asynv save --- .../ViewModels/TodoItemViewModel.cs | 32 +++++++++++++------ 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoItemViewModel.cs b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoItemViewModel.cs index ae890ab3..935932a5 100644 --- a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoItemViewModel.cs +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoItemViewModel.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.IO; using System.Threading; using System.Threading.Tasks; using CommunityToolkit.Mvvm.ComponentModel; @@ -39,23 +40,36 @@ public TodoItemViewModel(TodoItem item, TodoListViewModel parent, AppDbContext c public bool IsChecked { - get { return _isChecked; } + get { return this._isChecked; } set { - UpdateIsChecked(value); + var oldValue = this._isChecked; + if (SetProperty(ref this._isChecked, value)) + { + SaveIsChecked(value, oldValue); + } } } - - private async void UpdateIsChecked(bool value) + + private async void SaveIsChecked(bool value, bool oldValue) { - await UpdateIsCheckedAsync(value); + await SaveIsCheckedAsync(value, oldValue); } - private async Task UpdateIsCheckedAsync(bool newValue, CancellationToken cancellationToken = default) + // a counter that can be used to track save requests. Only used to demonstrate an exception after every third + // save operation. + int updateCounter = 0; + + private async Task SaveIsCheckedAsync(bool newValue, bool oldValue, CancellationToken cancellationToken = default) { try { TodoItem? storedItem = await context.TodoItems.FindAsync([GetToDoItem().Id], cancellationToken); + + if (++this.updateCounter % 3 == 0) + { + throw new IOException("Unable to save the item a third time. Please try again."); + } if (storedItem is not null) { @@ -66,18 +80,16 @@ private async Task UpdateIsCheckedAsync(bool newValue, CancellationToken cancell _ = await context.SaveChangesAsync(cancellationToken); parent.ShowInfoAlert("Saved changes successfully"); - SetProperty(ref this._isChecked, storedItem.IsComplete); } else { - parent.ShowErrorAlert("Item not found"); - OnPropertyChanged(nameof(IsChecked)); // Notify the UI about the current value + throw new Exception("Item not found"); } } catch (Exception ex) { + SetProperty(ref this._isChecked, oldValue, nameof(IsChecked)); // Notify the UI about the current value parent.ShowErrorAlert(ex.Message); - OnPropertyChanged(nameof(IsChecked)); // Notify the UI about the current value } } From 8a0f9b0ce1b2161400a704b809776399f3a48f21 Mon Sep 17 00:00:00 2001 From: timunie Date: Sun, 24 Nov 2024 22:43:03 +0100 Subject: [PATCH 05/13] WIP add some debug data --- .../TodoApp.Avalonia/App.axaml | 1 + .../TodoApp.Avalonia/App.axaml.cs | 35 ++++++++++----- .../TodoApp.Avalonia/Database/AppDbContext.cs | 31 ++++++++----- .../Database/DbContextInitializer.cs | 12 +++-- .../TodoApp.Avalonia/Database/ToDoItem.cs | 2 +- .../Services/DialogManager.cs | 5 ++- .../ViewModels/DesingTimeViewModels.cs | 18 ++++++++ .../ViewModels/TodoItemViewModel.cs | 45 ++++++++++++------- .../ViewModels/TodoListViewModel.cs | 3 +- .../TodoApp.Avalonia/Views/MainView.axaml | 35 ++++++++------- .../TodoApp.Avalonia/Views/MainWindow.axaml | 3 +- 11 files changed, 131 insertions(+), 59 deletions(-) create mode 100644 samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/DesingTimeViewModels.cs diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/App.axaml b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/App.axaml index b6267126..093f805a 100644 --- a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/App.axaml +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/App.axaml @@ -8,6 +8,7 @@ M 16.500001 0 C 15.52778 0 14.688382 0.35533588 14.101563 0.87695315 C 13.514743 1.3985704 13.165432 2.0458273 12.939454 2.6484376 C 12.757473 3.1337185 12.652358 3.6048008 12.589844 4.0000001 L 3.0000001 4.0000001 A 1 1 0 0 0 2.0000001 5.0000002 A 1 1 0 0 0 3.0000001 6.0000002 L 4.0253908 6.0000002 A 1 1 0 0 0 4.0078126 6.1250002 L 7.1171877 31.000001 L 25.882813 31.000001 L 28.992188 6.1250002 A 1 1 0 0 0 28.996095 6.0000002 L 30.000001 6.0000002 A 1 1 0 0 0 31.000001 5.0000002 A 1 1 0 0 0 30.000001 4.0000001 L 20.410157 4.0000001 C 20.347644 3.6048008 20.24253 3.1337185 20.060548 2.6484376 C 19.834569 2.0458273 19.485258 1.3985704 18.898438 0.87695315 C 18.31162 0.35533585 17.472221 -7.4014797e-17 16.500001 0 z M 16.500001 2.0000001 C 17.027777 2.0000001 17.313384 2.1446656 17.570313 2.3730469 C 17.827243 2.6014283 18.040434 2.9541747 18.189454 3.3515626 C 18.271334 3.5699097 18.330561 3.7916862 18.375001 4.0000001 L 14.625 4.0000001 C 14.66944 3.7916862 14.728668 3.5699097 14.810547 3.3515626 C 14.959568 2.9541747 15.172758 2.6014283 15.429688 2.3730469 C 15.686617 2.1446655 15.972223 2.0000001 16.500001 2.0000001 z M 6.0078127 6.0000002 L 26.992188 6.0000002 L 24.117188 29.000001 L 8.8828128 29.000001 L 6.0078127 6.0000002 z M 16.500001 7.9199221 A 1 1 0 0 0 15.5 8.9199222 L 15.5 27.402345 A 1 1 0 0 0 16.500001 28.402345 A 1 1 0 0 0 17.500001 27.402345 L 17.500001 8.9199222 A 1 1 0 0 0 16.500001 7.9199221 z M 9.8886722 8.0058596 A 1 1 0 0 0 9.0058597 9.1113284 L 11.00586 27.111329 A 1 1 0 0 0 12.111329 27.994141 A 1 1 0 0 0 12.994141 26.888673 L 10.994141 8.8886722 A 1 1 0 0 0 9.8886722 8.0058596 z M 23.111329 8.0058596 A 1 1 0 0 0 22.00586 8.8886722 L 20.00586 26.888673 A 1 1 0 0 0 20.888673 27.994141 A 1 1 0 0 0 21.994141 27.111329 L 23.994141 9.1113284 A 1 1 0 0 0 23.111329 8.0058596 z M 57.070314 2.7402345 C 48.797905 2.7402345 42.070314 9.4678252 42.070314 17.740235 C 42.070314 26.012646 48.797905 32.740235 57.070314 32.740235 C 65.342725 32.740235 72.070315 26.012646 72.070315 17.740235 C 72.070315 9.4678252 65.342725 2.7402345 57.070314 2.7402345 z M 57.070314 4.7402345 C 64.261847 4.7402345 70.070315 10.548703 70.070315 17.740235 C 70.070315 24.931768 64.261847 30.740235 57.070314 30.740235 C 49.878782 30.740235 44.070314 24.931768 44.070314 17.740235 C 44.070314 10.548703 49.878782 4.7402345 57.070314 4.7402345 z M 63.972658 10.779297 A 1 1 0 0 0 63.285158 11.115235 L 54.007814 21.621094 L 50.865236 17.949219 A 1 1 0 0 0 49.45508 17.837891 A 1 1 0 0 0 49.345705 19.248047 L 53.982424 24.669923 L 64.785158 12.439454 A 1 1 0 0 0 64.697268 11.029297 A 1 1 0 0 0 63.972658 10.779297 z + M 187.34323 0 C 152.30526 0 118.28156 9.9889238 88.951587 28.887905 C 70.367606 40.861893 54.245043 56.032253 41.221056 73.593235 L 2.0808211 34.641314 L 2.0808211 148.00624 L 115.99102 148.00624 L 62.772216 95.042275 C 90.904188 54.899315 137.49628 29.999987 187.34323 29.999987 C 271.08614 29.999987 339.21693 98.129776 339.21693 181.87369 L 369.21692 181.87369 C 369.21692 81.587792 287.62912 0 187.34323 0 z M 14.531083 201.87524 C 14.531083 302.16114 96.118875 383.74894 196.40477 383.74894 C 231.44274 383.74894 265.46744 373.76001 294.79641 354.86103 C 313.38039 342.88604 329.50296 327.71575 342.52694 310.15476 L 381.66624 349.10669 L 381.66624 235.74176 L 267.75698 235.74176 L 320.97578 288.70666 C 292.84381 328.84862 246.25172 353.74895 196.40477 353.74895 C 112.66086 353.74895 44.53107 285.61916 44.53107 201.87524 L 14.531083 201.87524 z diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/App.axaml.cs b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/App.axaml.cs index 344a4f0c..9f3e8184 100644 --- a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/App.axaml.cs +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/App.axaml.cs @@ -1,4 +1,5 @@ using System; +using System.IO; using Avalonia; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Data.Core; @@ -15,14 +16,25 @@ namespace TodoApp.Avalonia; -public partial class App : Application +public partial class App : Application, IDisposable { private readonly SqliteConnection dbConnection; public IServiceProvider Services { get; } - + public string Test { get; } = "test"; + public App() { - this.dbConnection = new SqliteConnection("Data Source=:memory:"); +#if DEBUG + string dbFile = ":memory:"; +#else + string dbFile = Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), + "DataSylc.Avalonia.Sample", + "TodoList.db")"; +#endif + + this.dbConnection = new SqliteConnection($"Data Source={dbFile}"); + this.dbConnection.Open(); // Create the IoC Services provider. @@ -32,7 +44,7 @@ public App() .AddDbContext(options => options.UseSqlite(this.dbConnection)) .BuildServiceProvider(); } - + public override void Initialize() { AvaloniaXamlLoader.Load(this); @@ -40,7 +52,6 @@ public override void Initialize() public override void OnFrameworkInitializationCompleted() { - if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { // Line below is needed to remove Avalonia data validation. @@ -53,19 +64,19 @@ public override void OnFrameworkInitializationCompleted() singleViewPlatform.MainView = new MainView { DataContext = GetRequiredService() }; } - + // Initialize the database after DataContext was set InitializeDatabase(); - + base.OnFrameworkInitializationCompleted(); } - - private void InitializeDatabase() + + private async void InitializeDatabase() { using IServiceScope scope = Services.CreateScope(); IDbInitializer initializer = scope.ServiceProvider.GetRequiredService(); - initializer.Initialize(); - + await initializer.InitializeAsync(); + Dispatcher.UIThread.Post( () => GetRequiredService().ShowInfoAlert("All data loaded"), DispatcherPriority.Loaded); @@ -83,6 +94,7 @@ public static TService GetRequiredService() where TService : notnull => ((App)App.Current!).Services.GetRequiredService(); #region IDisposable + private bool hasDisposed; protected virtual void Dispose(bool disposing) @@ -103,5 +115,6 @@ public void Dispose() Dispose(disposing: true); GC.SuppressFinalize(this); } + #endregion } \ No newline at end of file diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/AppDbContext.cs b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/AppDbContext.cs index d66bab53..fbbde0e0 100644 --- a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/AppDbContext.cs +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/AppDbContext.cs @@ -24,16 +24,27 @@ public class AppDbContext(DbContextOptions options) : DbContext(op public async Task SynchronizeAsync(CancellationToken cancellationToken = default) { - //PushResult pushResult = await this.PushAsync(cancellationToken); - //if (!pushResult.IsSuccessful) - //{ - // throw new ApplicationException($"Push failed: {pushResult.FailedRequests.FirstOrDefault().Value.ReasonPhrase}"); - //} + // PushResult pushResult = await this.PushAsync(cancellationToken); + // if (!pushResult.IsSuccessful) + // { + // throw new ApplicationException($"Push failed: {pushResult.FailedRequests.FirstOrDefault().Value.ReasonPhrase}"); + // } + // + // PullResult pullResult = await this.PullAsync(cancellationToken); + // if (!pullResult.IsSuccessful) + // { + // throw new ApplicationException($"Pull failed: {pullResult.FailedRequests.FirstOrDefault().Value.ReasonPhrase}"); + // } + } + + #if DEBUG + internal async Task AddSampleDataAsync(CancellationToken cancellationToken = default) + { + TodoItems.Add(new TodoItem() { Content = "Say Hello", IsComplete = true }); + TodoItems.Add(new TodoItem() { Content = "Learn DataSync", IsComplete = false }); + TodoItems.Add(new TodoItem() { Content = "Learn Avalonia", IsComplete = false }); - //PullResult pullResult = await this.PullAsync(cancellationToken); - //if (!pullResult.IsSuccessful) - //{ - // throw new ApplicationException($"Pull failed: {pullResult.FailedRequests.FirstOrDefault().Value.ReasonPhrase}"); - //} + await SaveChangesAsync(); } + #endif } \ No newline at end of file diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/DbContextInitializer.cs b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/DbContextInitializer.cs index ad37cf27..27dc8854 100644 --- a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/DbContextInitializer.cs +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/DbContextInitializer.cs @@ -20,10 +20,16 @@ public class DbContextInitializer(AppDbContext context) : IDbInitializer public void Initialize() { _ = context.Database.EnsureCreated(); - // Task.Run(async () => await context.SynchronizeAsync()); + Task.Run(async () => await context.SynchronizeAsync()); } /// - public Task InitializeAsync(CancellationToken cancellationToken = default) - => context.Database.EnsureCreatedAsync(cancellationToken); + public async Task InitializeAsync(CancellationToken cancellationToken = default) + { + await context.Database.EnsureCreatedAsync(cancellationToken); + + #if DEBUG + await context.AddSampleDataAsync(); + #endif + } } \ No newline at end of file diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/ToDoItem.cs b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/ToDoItem.cs index 2724ec72..0928cee0 100644 --- a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/ToDoItem.cs +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/ToDoItem.cs @@ -6,6 +6,6 @@ namespace TodoApp.Avalonia.Database; public class TodoItem : OfflineClientEntity { - public string Title { get; set; } = string.Empty; + public string Content { get; set; } = string.Empty; public bool IsComplete { get; set; } = false; } diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Services/DialogManager.cs b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Services/DialogManager.cs index 18978f43..460d52e9 100644 --- a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Services/DialogManager.cs +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Services/DialogManager.cs @@ -96,13 +96,14 @@ public static void ShowErrorAlert(this object context, string message) { MainView view = (MainView)DialogManager.GetVisualForContext(context)!; - view.ControlNotifications.Show(message, NotificationType.Warning); + view.ControlNotifications.Show(message, NotificationType.Error); } public static void ShowInfoAlert(this object context, string message) { + if (Design.IsDesignMode) return; MainView view = (MainView)DialogManager.GetVisualForContext(context)!; - + view.ControlNotifications.Show(message, NotificationType.Information, TimeSpan.FromSeconds(3)); } } \ No newline at end of file diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/DesingTimeViewModels.cs b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/DesingTimeViewModels.cs new file mode 100644 index 00000000..1e09a24f --- /dev/null +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/DesingTimeViewModels.cs @@ -0,0 +1,18 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using Avalonia; +using Microsoft.Extensions.DependencyInjection; +using TodoApp.Avalonia.Database; + +namespace TodoApp.Avalonia.ViewModels; +#if DEBUG +public static class DesingTimeViewModels +{ + + public static TodoListViewModel TodoListDesignerViewModel => + (Application.Current as App)?.Services.GetRequiredService() ?? throw new InvalidOperationException(); +} +#endif diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoItemViewModel.cs b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoItemViewModel.cs index 935932a5..8154bd1c 100644 --- a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoItemViewModel.cs +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoItemViewModel.cs @@ -25,27 +25,30 @@ public partial class TodoItemViewModel(TodoListViewModel parent, AppDbContext co public TodoItemViewModel(TodoItem item, TodoListViewModel parent, AppDbContext context) : this(parent, context) { // Init the properties with the given values - this._isChecked = item.IsComplete; - this._content = item.Title; + this._IsComplete = item.IsComplete; + this._content = item.Content; this._todoItem = item; } + // NOTE: This property is made without source generator. Uncomment the line below to use the source generator + // [ObservableProperty] + private bool _IsComplete; + /// /// Gets or sets the checked status of each item /// - // NOTE: This property is made without source generator. Uncomment the line below to use the source generator - // [ObservableProperty] - private bool _isChecked; - - public bool IsChecked + public bool IsComplete { - get { return this._isChecked; } + get { return this._IsComplete; } set { - var oldValue = this._isChecked; - if (SetProperty(ref this._isChecked, value)) + // Stpre the old value in order to undo the changes, if the save operation failed + bool oldValue = this._IsComplete; + + if (SetProperty(ref this._IsComplete, value)) { + // save the item in case the have an updated value SaveIsChecked(value, oldValue); } } @@ -64,31 +67,38 @@ private async Task SaveIsCheckedAsync(bool newValue, bool oldValue, Cancellation { try { + // lookup the stored item TodoItem? storedItem = await context.TodoItems.FindAsync([GetToDoItem().Id], cancellationToken); + // this is just to show how errors are handled. Feel free to comment it. if (++this.updateCounter % 3 == 0) { + await Task.Delay(500); throw new IOException("Unable to save the item a third time. Please try again."); } if (storedItem is not null) { + // update the stored item storedItem.IsComplete = newValue; // Store the updated item in the database _ = context.TodoItems.Update(storedItem); _ = await context.SaveChangesAsync(cancellationToken); + // Show an info to the user parent.ShowInfoAlert("Saved changes successfully"); } else { - throw new Exception("Item not found"); + // If no item was found, throw an exection + throw new NullReferenceException("Item not found"); } } catch (Exception ex) { - SetProperty(ref this._isChecked, oldValue, nameof(IsChecked)); // Notify the UI about the current value + // Set the Property back to it's old value + SetProperty(ref this._IsComplete, oldValue, nameof(IsComplete)); parent.ShowErrorAlert(ex.Message); } } @@ -100,18 +110,23 @@ private async Task SaveIsCheckedAsync(bool newValue, bool oldValue, Cancellation [ObservableProperty] private string? _content; /// - /// Gets a ToDoItem of this ViewModel + /// Gets a ToDoItem for this Item-ViewModel /// /// The ToDoItem public TodoItem GetToDoItem() { if (this._todoItem is not null) { - this._todoItem.Title = Content; + this._todoItem.Content = Content ?? string.Empty; + this._todoItem.IsComplete = IsComplete; return this._todoItem; } // if no todoItem model is found, return a new one - return new TodoItem() { IsComplete = this.IsChecked, Title = this.Content }; + return new TodoItem() + { + IsComplete = this.IsComplete, + Content = this.Content ?? string.Empty + }; } } \ No newline at end of file diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoListViewModel.cs b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoListViewModel.cs index 615d707f..92f3260e 100644 --- a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoListViewModel.cs +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoListViewModel.cs @@ -34,7 +34,7 @@ private async Task AddItemAsync(CancellationToken cancellationToken) TodoItem addition = new() { Id = Guid.NewGuid().ToString("N"), - Title = NewItemContent ?? throw new InvalidOperationException("New item content may not be null or empty") + Content = NewItemContent ?? throw new InvalidOperationException("New item content may not be null or empty") }; // Add the item to the database @@ -77,6 +77,7 @@ private async Task RemoveItemAsync(TodoItemViewModel item) // Remove the given item from the list Items.Remove(item); + // Remove it also from the data base _ = context.TodoItems.Remove(item.GetToDoItem()); _ = await context.SaveChangesAsync(); } diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Views/MainView.axaml b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Views/MainView.axaml index 07d0cf90..6e3b60bb 100644 --- a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Views/MainView.axaml +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Views/MainView.axaml @@ -1,22 +1,27 @@ - - - - - - + - + - - + @@ -27,7 +32,7 @@ - + diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Views/MainWindow.axaml b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Views/MainWindow.axaml index 8d0912a9..7c908659 100644 --- a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Views/MainWindow.axaml +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Views/MainWindow.axaml @@ -4,7 +4,8 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:views="clr-namespace:TodoApp.Avalonia.Views" - mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" + mc:Ignorable="d" + Width="300" Height="500" x:Class="TodoApp.Avalonia.Views.MainWindow" Icon="/Assets/avalonia-logo.ico" Title="TodoApp.Avalonia"> From 2a98271aeedfd1dac5c339509da5fd0ebd4dee5a Mon Sep 17 00:00:00 2001 From: Tim Date: Mon, 25 Nov 2024 18:11:16 +0100 Subject: [PATCH 06/13] Improving the debug sample --- .../TodoApp.Avalonia/App.axaml | 6 ++++- .../TodoApp.Avalonia/Database/AppDbContext.cs | 25 +++++++++++++------ .../ViewModels/TodoItemViewModel.cs | 4 ++- .../TodoApp.Avalonia/Views/MainWindow.axaml | 3 ++- 4 files changed, 28 insertions(+), 10 deletions(-) diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/App.axaml b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/App.axaml index 093f805a..058e67ce 100644 --- a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/App.axaml +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/App.axaml @@ -21,6 +21,11 @@ + + + - \ No newline at end of file diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/AppDbContext.cs b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/AppDbContext.cs index fbbde0e0..881cc87b 100644 --- a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/AppDbContext.cs +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/AppDbContext.cs @@ -2,9 +2,13 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; using System.Threading; using System.Threading.Tasks; +using Avalonia; using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using TodoApp.Avalonia.ViewModels; namespace TodoApp.Avalonia.Database; @@ -36,15 +40,22 @@ public async Task SynchronizeAsync(CancellationToken cancellationToken = default // throw new ApplicationException($"Pull failed: {pullResult.FailedRequests.FirstOrDefault().Value.ReasonPhrase}"); // } } - - #if DEBUG + +#if DEBUG internal async Task AddSampleDataAsync(CancellationToken cancellationToken = default) { - TodoItems.Add(new TodoItem() { Content = "Say Hello", IsComplete = true }); - TodoItems.Add(new TodoItem() { Content = "Learn DataSync", IsComplete = false }); - TodoItems.Add(new TodoItem() { Content = "Learn Avalonia", IsComplete = false }); - + await TodoItems.AddRangeAsync( + new TodoItem() { Id = Guid.NewGuid().ToString("N"), Content = """Say "Hello" to DataSync and Avalonia""" , IsComplete = true }, + new TodoItem() { Id = Guid.NewGuid().ToString("N"), Content = "Learn DataSync", IsComplete = false }, + new TodoItem() { Id = Guid.NewGuid().ToString("N"), Content = "Learn Avalonia", IsComplete = false }); + await SaveChangesAsync(); + + // Make sure the ViewModel has fetched the latest changes + TodoListViewModel todoListViewModel = + (Application.Current as App)?.Services.GetRequiredService()!; + + await todoListViewModel.RefreshItemsAsync(); } - #endif +#endif } \ No newline at end of file diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoItemViewModel.cs b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoItemViewModel.cs index 8154bd1c..00b8dd75 100644 --- a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoItemViewModel.cs +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoItemViewModel.cs @@ -65,10 +65,11 @@ private async void SaveIsChecked(bool value, bool oldValue) private async Task SaveIsCheckedAsync(bool newValue, bool oldValue, CancellationToken cancellationToken = default) { + TodoItem? storedItem = null; try { // lookup the stored item - TodoItem? storedItem = await context.TodoItems.FindAsync([GetToDoItem().Id], cancellationToken); + storedItem = await context.TodoItems.FindAsync([GetToDoItem().Id], cancellationToken); // this is just to show how errors are handled. Feel free to comment it. if (++this.updateCounter % 3 == 0) @@ -99,6 +100,7 @@ private async Task SaveIsCheckedAsync(bool newValue, bool oldValue, Cancellation { // Set the Property back to it's old value SetProperty(ref this._IsComplete, oldValue, nameof(IsComplete)); + if (storedItem is not null) storedItem.IsComplete = oldValue; parent.ShowErrorAlert(ex.Message); } } diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Views/MainWindow.axaml b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Views/MainWindow.axaml index 7c908659..353cc5fe 100644 --- a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Views/MainWindow.axaml +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Views/MainWindow.axaml @@ -5,9 +5,10 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:views="clr-namespace:TodoApp.Avalonia.Views" mc:Ignorable="d" - Width="300" Height="500" + Width="450" Height="800" x:Class="TodoApp.Avalonia.Views.MainWindow" Icon="/Assets/avalonia-logo.ico" + Design.DataContext="{x:Static vm:DesingTimeViewModels.TodoListDesignerViewModel}" Title="TodoApp.Avalonia"> From 21804d24d28ce8cb1776e6e8dc10445b09fddf4e Mon Sep 17 00:00:00 2001 From: Tim Date: Mon, 25 Nov 2024 18:14:06 +0100 Subject: [PATCH 07/13] order items by ID --- .../TodoApp.Avalonia/ViewModels/TodoListViewModel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoListViewModel.cs b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoListViewModel.cs index 92f3260e..4ebbf529 100644 --- a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoListViewModel.cs +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoListViewModel.cs @@ -92,7 +92,7 @@ public async Task RefreshItemsAsync(CancellationToken cancellationToken = defaul await context.SynchronizeAsync(cancellationToken); // Retrieve the items from the service - List dbItems = await context.TodoItems.ToListAsync(cancellationToken); + List dbItems = await context.TodoItems.OrderBy(item => item.Id).ToListAsync(cancellationToken); // Replace the items in the collection Items.Clear(); From 7d95c5a51721664aa7b9ff837a92e86687afee65 Mon Sep 17 00:00:00 2001 From: Tim Date: Wed, 27 Nov 2024 17:21:35 +0100 Subject: [PATCH 08/13] Adding Avalonia.md to the docs --- docs/content/samples/todoapp/avalonia.md | 76 ++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 docs/content/samples/todoapp/avalonia.md diff --git a/docs/content/samples/todoapp/avalonia.md b/docs/content/samples/todoapp/avalonia.md new file mode 100644 index 00000000..582ed42c --- /dev/null +++ b/docs/content/samples/todoapp/avalonia.md @@ -0,0 +1,76 @@ ++++ +title = "Avalonia" ++++ + +## Run the application first + +The Avalonia sample uses an in-memory Sqlite store (debug mode) or a file Sqlite store (Release mode) for storing its data. The sample can run on Desktop, Mobile and Browser. To run the application locally: + +* [Configure Visual Studio for Avalonia development](https://docs.avaloniaui.net/docs/welcome). +* Open `samples/todoapp/Samples.TodoApp.sln` in Visual Studio. +* In the Solution Explorer, right-click the `TodoApp.Avalonia/TodoApp.Avalonia.Desktop` project, then select **Set as Startup Project**. +* Select a target (in the top bar), then press F5 to run the application. + +> [!TIP] +> We suggest to start testing and debugging using the Desktop App first. Once you feel confident, you can also try out Mobile or Browser version. + +> [!NOTE] +> If you bump into issues at this point, please visit [Avalonia.Docs](https://docs.avaloniaui.net) and [Avalonia.Samples](https://github.com/AvaloniaUI/Avalonia.Samples) for some basic getting-started tutorials. + +## Deploy a datasync server to Azure + +Before you begin adjusting the application for offline usage, you must [deploy a datasync service](../server.md). Make a note of the URI of the service before continuing. + +## Update the application for datasync operations + +All the changes are isolated to the `Database/AppDbContext.cs` file. + +1. Change the definition of the class so that it inherits from `OfflineDbContext`: + + ```csharp + public class AppDbContext(DbContextOptions options) : OfflineDbContext(options) + { + // Rest of the class + } + ``` + +2. Add the `OnDatasyncInitialization()` method: + + ```csharp + protected override void OnDatasyncInitialization(DatasyncOfflineOptionsBuilder optionsBuilder) + { + HttpClientOptions clientOptions = new() + { + Endpoint = new Uri("https://YOURSITEHERE.azurewebsites.net/"), + HttpPipeline = [new LoggingHandler()] + }; + _ = optionsBuilder.UseHttpClientOptions(clientOptions); + } + ``` + + Replace the Endpoint with the URI of your datasync service. + +3. Update the `SynchronizeAsync()` method. + + The `SynchronizeAsync()` method is used by the application to synchronize data to and from the datasync service. It is called primarily from the `MainViewModel` which drives the UI interactions for the main list. + + ```csharp + public async Task SynchronizeAsync(CancellationToken cancellationToken = default) + { + PushResult pushResult = await this.PushAsync(cancellationToken); + if (!pushResult.IsSuccessful) + { + throw new ApplicationException($"Push failed: {pushResult.FailedRequests.FirstOrDefault().Value.ReasonPhrase}"); + } + + PullResult pullResult = await this.PullAsync(cancellationToken); + if (!pullResult.IsSuccessful) + { + throw new ApplicationException($"Pull failed: {pullResult.FailedRequests.FirstOrDefault().Value.ReasonPhrase}"); + } + } + ``` + +You can now re-run your application. Watch the console logs to show the interactions with the datasync service. Press the refresh button to synchronize data with the cloud. When you restart the application, your changes will automatically populate the database again. + +Obviously, you will want to do much more in a "real world" application, including proper error handling, authentication, and using a Sqlite file instead of an in-memory database. This example shows off the minimum required to add datasync services to an application. From d27ec6e891b80b474f59473b164cf166d3457f07 Mon Sep 17 00:00:00 2001 From: Tim Date: Wed, 27 Nov 2024 18:12:34 +0100 Subject: [PATCH 09/13] minor readme improvement --- docs/content/samples/todoapp/avalonia.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/samples/todoapp/avalonia.md b/docs/content/samples/todoapp/avalonia.md index 582ed42c..93dca8ba 100644 --- a/docs/content/samples/todoapp/avalonia.md +++ b/docs/content/samples/todoapp/avalonia.md @@ -8,7 +8,7 @@ The Avalonia sample uses an in-memory Sqlite store (debug mode) or a file Sqlite * [Configure Visual Studio for Avalonia development](https://docs.avaloniaui.net/docs/welcome). * Open `samples/todoapp/Samples.TodoApp.sln` in Visual Studio. -* In the Solution Explorer, right-click the `TodoApp.Avalonia/TodoApp.Avalonia.Desktop` project, then select **Set as Startup Project**. +* In the Solution Explorer, expand the folder `TodoApp.Avalonia` and right-click the `TodoApp.Avalonia.Desktop` project, then select **Set as Startup Project**. * Select a target (in the top bar), then press F5 to run the application. > [!TIP] From 69f32e7e7c538691e8f2e682de1634584ca8c6f3 Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 28 Nov 2024 16:35:39 +0100 Subject: [PATCH 10/13] Improve AvaloniaSample - improved Messenger system - Added more comments and explanations --- .../TodoApp.Avalonia/App.axaml.cs | 43 ++-- .../TodoApp.Avalonia/Database/AppDbContext.cs | 16 +- .../Database/DbContextInitializer.cs | 15 +- .../Database/OfflineClientEntry.cs | 19 ++ .../TodoApp.Avalonia/Database/ToDoItem.cs | 7 + .../Services/DialogManager.cs | 223 +++++++++++------- .../TodoApp.Avalonia/Services/IDialogBus.cs | 13 + .../Services/INotificationService.cs | 18 ++ .../ViewModels/DesingTimeViewModels.cs | 8 +- .../ViewModels/TodoItemViewModel.cs | 55 +++-- .../ViewModels/TodoListViewModel.cs | 33 ++- .../TodoApp.Avalonia/Views/MainView.axaml | 44 ++-- .../TodoApp.Avalonia/Views/MainView.axaml.cs | 39 ++- .../TodoApp.Avalonia/Views/MainWindow.axaml | 2 +- 14 files changed, 354 insertions(+), 181 deletions(-) create mode 100644 samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Services/IDialogBus.cs create mode 100644 samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Services/INotificationService.cs diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/App.axaml.cs b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/App.axaml.cs index 9f3e8184..b3444e8d 100644 --- a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/App.axaml.cs +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/App.axaml.cs @@ -19,21 +19,19 @@ namespace TodoApp.Avalonia; public partial class App : Application, IDisposable { private readonly SqliteConnection dbConnection; + + /// + /// Gets an see to configure App-Services. + /// public IServiceProvider Services { get; } - public string Test { get; } = "test"; public App() { -#if DEBUG - string dbFile = ":memory:"; -#else - string dbFile = Path.Combine( - Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), - "DataSylc.Avalonia.Sample", - "TodoList.db")"; -#endif - - this.dbConnection = new SqliteConnection($"Data Source={dbFile}"); + // For the sample we use a SqLite-DB which is in memory only. Therefore, there is no data persistence available. + // Feel free to adjust the connection string as needed. + string connectionString = "Data Source=:memory:"; + + this.dbConnection = new SqliteConnection(connectionString); this.dbConnection.Open(); @@ -45,48 +43,49 @@ public App() .BuildServiceProvider(); } + /// public override void Initialize() { AvaloniaXamlLoader.Load(this); } + /// public override void OnFrameworkInitializationCompleted() { + // Line below is needed to remove Avalonia data validation. + // Without this line you will get duplicate validations from both Avalonia and CT + BindingPlugins.DataValidators.RemoveAt(0); + if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { - // Line below is needed to remove Avalonia data validation. - // Without this line you will get duplicate validations from both Avalonia and CT - BindingPlugins.DataValidators.RemoveAt(0); desktop.MainWindow = new MainWindow { DataContext = GetRequiredService() }; } else if (ApplicationLifetime is ISingleViewApplicationLifetime singleViewPlatform) { singleViewPlatform.MainView = new MainView { DataContext = GetRequiredService() }; } - - + // Initialize the database after DataContext was set InitializeDatabase(); base.OnFrameworkInitializationCompleted(); } + /// + /// This method initializes the database. + /// private async void InitializeDatabase() { using IServiceScope scope = Services.CreateScope(); IDbInitializer initializer = scope.ServiceProvider.GetRequiredService(); await initializer.InitializeAsync(); - - Dispatcher.UIThread.Post( - () => GetRequiredService().ShowInfoAlert("All data loaded"), - DispatcherPriority.Loaded); } /// - /// A helper method for getting a service from the services collection. + /// A helper method for getting a service from the -collection. /// /// - /// You can see this in action in the class. + /// You can see this in action in the class. /// /// The type of the service. /// An instance of the service diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/AppDbContext.cs b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/AppDbContext.cs index 881cc87b..8bf96c85 100644 --- a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/AppDbContext.cs +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/AppDbContext.cs @@ -5,10 +5,7 @@ using System; using System.Threading; using System.Threading.Tasks; -using Avalonia; using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.DependencyInjection; -using TodoApp.Avalonia.ViewModels; namespace TodoApp.Avalonia.Database; @@ -41,7 +38,9 @@ public async Task SynchronizeAsync(CancellationToken cancellationToken = default // } } -#if DEBUG + /// + /// Adds some sample data to the database + /// internal async Task AddSampleDataAsync(CancellationToken cancellationToken = default) { await TodoItems.AddRangeAsync( @@ -49,13 +48,6 @@ await TodoItems.AddRangeAsync( new TodoItem() { Id = Guid.NewGuid().ToString("N"), Content = "Learn DataSync", IsComplete = false }, new TodoItem() { Id = Guid.NewGuid().ToString("N"), Content = "Learn Avalonia", IsComplete = false }); - await SaveChangesAsync(); - - // Make sure the ViewModel has fetched the latest changes - TodoListViewModel todoListViewModel = - (Application.Current as App)?.Services.GetRequiredService()!; - - await todoListViewModel.RefreshItemsAsync(); + await SaveChangesAsync(cancellationToken); } -#endif } \ No newline at end of file diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/DbContextInitializer.cs b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/DbContextInitializer.cs index 27dc8854..0de66b0e 100644 --- a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/DbContextInitializer.cs +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/DbContextInitializer.cs @@ -5,15 +5,16 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore.Infrastructure; +using TodoApp.Avalonia.ViewModels; namespace TodoApp.Avalonia.Database; /// -/// Use this class to initialize the database. In this sample, we just create -/// the database using . However, you +/// Use this class to initialize the database. In this sample, we just create +/// the database using . However, you /// may want to use migrations. /// -/// The context for the database. +/// The for the database. public class DbContextInitializer(AppDbContext context) : IDbInitializer { /// @@ -28,8 +29,10 @@ public async Task InitializeAsync(CancellationToken cancellationToken = default) { await context.Database.EnsureCreatedAsync(cancellationToken); - #if DEBUG - await context.AddSampleDataAsync(); - #endif + await context.AddSampleDataAsync(cancellationToken); + + // Make sure the ViewModel has fetched the latest changes and is up to date + TodoListViewModel todoListViewModel = App.GetRequiredService(); + await todoListViewModel.RefreshItemsAsync(cancellationToken); } } \ No newline at end of file diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/OfflineClientEntry.cs b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/OfflineClientEntry.cs index 3d6373fb..05642b04 100644 --- a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/OfflineClientEntry.cs +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/OfflineClientEntry.cs @@ -12,9 +12,28 @@ namespace TodoApp.Avalonia.Database; /// public abstract class OfflineClientEntity { + /// + /// Gets or sets the ID of this item. + /// + /// + /// The default is . + /// + [Key] public string Id { get; set; } = Guid.NewGuid().ToString("N"); + + /// + /// Gets or sets the last update time. + /// public DateTimeOffset? UpdatedAt { get; set; } + + /// + /// Gets or sets the version info. + /// public string? Version { get; set; } + + /// + /// Gets or sets whether the item was deleted. + /// public bool Deleted { get; set; } } \ No newline at end of file diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/ToDoItem.cs b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/ToDoItem.cs index 0928cee0..32d6032f 100644 --- a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/ToDoItem.cs +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/ToDoItem.cs @@ -6,6 +6,13 @@ namespace TodoApp.Avalonia.Database; public class TodoItem : OfflineClientEntity { + /// + /// Gets or sets the content. + /// public string Content { get; set; } = string.Empty; + + /// + /// Gets or sets if the task was completed. + /// public bool IsComplete { get; set; } = false; } diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Services/DialogManager.cs b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Services/DialogManager.cs index 460d52e9..85469bd4 100644 --- a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Services/DialogManager.cs +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Services/DialogManager.cs @@ -4,106 +4,147 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; using Avalonia; using Avalonia.Controls; using Avalonia.Controls.Notifications; -using Avalonia.Platform.Storage; -using TodoApp.Avalonia.Views; namespace TodoApp.Avalonia.Services; - public class DialogManager - { - private static readonly Dictionary RegistrationMapper = - new Dictionary(); - - static DialogManager() - { - RegisterProperty.Changed.AddClassHandler(RegisterChanged); - } - - private static void RegisterChanged(Visual sender, AvaloniaPropertyChangedEventArgs e) - { - if (sender is null) - { - throw new InvalidOperationException("The DialogManager can only be registered on a Visual"); - } - - // Unregister any old registered context - if (e.OldValue != null) - { - RegistrationMapper.Remove(e.OldValue); - } - - // Register any new context - if (e.NewValue != null) - { - RegistrationMapper.Add(e.NewValue, sender); - } - } - - /// - /// This property handles the registration of Views and ViewModel - /// - public static readonly AttachedProperty RegisterProperty = AvaloniaProperty.RegisterAttached( - "Register"); - - /// - /// Accessor for Attached property . - /// - public static void SetRegister(AvaloniaObject element, object value) - { - element.SetValue(RegisterProperty, value); - } - - /// - /// Accessor for Attached property . - /// - public static object? GetRegister(AvaloniaObject element) - { - return element.GetValue(RegisterProperty); - } - - /// - /// Gets the associated for a given context. Returns null, if none was registered - /// - /// The context to lookup - /// The registered Visual for the context or null if none was found - public static Visual? GetVisualForContext(object context) - { - return RegistrationMapper.TryGetValue(context, out var result) ? result : null; - } - - /// - /// Gets the parent for the given context. Returns null, if no TopLevel was found - /// - /// The context to lookup - /// The registered TopLevel for the context or null if none was found - public static TopLevel? GetTopLevelForContext(object context) - { - return TopLevel.GetTopLevel(GetVisualForContext(context)); - } - } - - /// - /// A helper class to manage dialogs via extension methods. Add more on your own - /// - public static class DialogHelper - { - public static void ShowErrorAlert(this object context, string message) +/// +/// The DialogManager is used to connect a given (most likely your ViewModel) to +/// a . +/// +/// +/// See also: Avalonia.Samples → ViewInteraction-Sample +/// +public class DialogManager +{ + + /// + /// This is a dictionary which stores the mappings between the and + /// + private static readonly Dictionary RegistrationMapper = + new Dictionary(); + + static DialogManager() + { + RegisterProperty.Changed.AddClassHandler(RegisterChanged); + } + + /// + /// This property handles the registration of Views and ViewModel + /// + public static readonly AttachedProperty RegisterProperty = + AvaloniaProperty.RegisterAttached( + "Register"); + + /// + /// Accessor for Attached property . + /// + public static IDialogBus? GetRegister(AvaloniaObject element) + { + return element.GetValue(RegisterProperty); + } + + /// + /// Accessor for Attached property . + /// + public static void SetRegister(AvaloniaObject element, IDialogBus value) + { + element.SetValue(RegisterProperty, value); + } + + /// + /// Called when a new Visual is registered + /// + /// If no Visual was provided + private static void RegisterChanged(Visual sender, AvaloniaPropertyChangedEventArgs e) + { + if (sender is null) { - MainView view = (MainView)DialogManager.GetVisualForContext(context)!; + throw new InvalidOperationException("The DialogManager can only be registered on a Visual"); + } - view.ControlNotifications.Show(message, NotificationType.Error); + // Unregister any old registered context + if (e.OldValue != null) + { + RegistrationMapper.Remove((IDialogBus)e.OldValue); } - public static void ShowInfoAlert(this object context, string message) + // Register any new context + if (e.NewValue != null) { - if (Design.IsDesignMode) return; - MainView view = (MainView)DialogManager.GetVisualForContext(context)!; - - view.ControlNotifications.Show(message, NotificationType.Information, TimeSpan.FromSeconds(3)); + RegistrationMapper.Add((IDialogBus)e.NewValue, sender); } - } \ No newline at end of file + } + + /// + /// Gets the associated for a given context. Returns null, if none was registered + /// + /// The context to lookup + /// The registered Visual for the context or null if none was found + public static Visual? GetVisualForContext(IDialogBus context) + { + return RegistrationMapper.TryGetValue(context, out Visual? result) ? result : null; + } + + /// + /// Gets the parent for the given context. Returns null, if no TopLevel was found + /// + /// The context to lookup + /// The registered TopLevel for the context or null if none was found + public static TopLevel? GetTopLevelForContext(IDialogBus context) + { + return TopLevel.GetTopLevel(GetVisualForContext(context)); + } +} + +/// +/// A helper class to manage dialogs via extension methods. Add more on your own +/// +public static class DialogHelper +{ + /// + /// Displays a message to the user with an error-style. + /// + /// The context to find the mapped Visual + /// The message to display + public static void ShowErrorAlert(this IDialogBus context, string message) + { + ShowAlert(context, message, NotificationType.Error); + } + + /// + /// Displays a message to the user with an info-style. + /// + /// The context to find the mapped Visual + /// The message to display + public static void ShowInfoAlert(this IDialogBus context, string message) + { + ShowAlert(context, message, NotificationType.Information); + } + + /// + /// Displays a message to the user with an success-style. + /// + /// The context to find the mapped Visual + /// The message to display + public static void ShowSuccessAlert(this IDialogBus context, string message) + { + ShowAlert(context, message, NotificationType.Success); + } + + /// + /// Helper method to display messages + /// + /// The context to find the mapped Visual + /// The message to display + /// The to use + public static void ShowAlert(this IDialogBus context, string message, NotificationType type) + { + if (Design.IsDesignMode) return; + INotificationService view = (INotificationService)DialogManager.GetVisualForContext(context)!; + + view.NotificationManager.Show(message, type, TimeSpan.FromSeconds(3)); + } +} \ No newline at end of file diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Services/IDialogBus.cs b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Services/IDialogBus.cs new file mode 100644 index 00000000..1cd99c78 --- /dev/null +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Services/IDialogBus.cs @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace TodoApp.Avalonia.Services; + +/// +/// This interface is used to indicate that a class can be used to communicate with the View +/// +public interface IDialogBus +{ + +} \ No newline at end of file diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Services/INotificationService.cs b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Services/INotificationService.cs new file mode 100644 index 00000000..f2df5473 --- /dev/null +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Services/INotificationService.cs @@ -0,0 +1,18 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Avalonia.Controls.Notifications; + +namespace TodoApp.Avalonia.Services; + +/// +/// An interface which a View needs to implement in order to show Notifications sent from any +/// +public interface INotificationService +{ + /// + /// Gets the NotificationManager which is used to display a NotificationMessage + /// + public WindowNotificationManager NotificationManager { get; } +} \ No newline at end of file diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/DesingTimeViewModels.cs b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/DesingTimeViewModels.cs index 1e09a24f..a8226ff7 100644 --- a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/DesingTimeViewModels.cs +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/DesingTimeViewModels.cs @@ -5,13 +5,15 @@ using System; using Avalonia; using Microsoft.Extensions.DependencyInjection; -using TodoApp.Avalonia.Database; namespace TodoApp.Avalonia.ViewModels; #if DEBUG -public static class DesingTimeViewModels + +/// +/// Holds some sample ViewModels to be shown in the Designer. +/// +public static class DesignTimeViewModels { - public static TodoListViewModel TodoListDesignerViewModel => (Application.Current as App)?.Services.GetRequiredService() ?? throw new InvalidOperationException(); } diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoItemViewModel.cs b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoItemViewModel.cs index 00b8dd75..84104d0a 100644 --- a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoItemViewModel.cs +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoItemViewModel.cs @@ -12,57 +12,76 @@ namespace TodoApp.Avalonia.ViewModels; -public partial class TodoItemViewModel(TodoListViewModel parent, AppDbContext context) : ViewModelBase +/// +/// A ViewModel used to represent a . +/// +/// the to send notifications to the user +/// the to use +public partial class TodoItemViewModel(IDialogBus dialogBus, AppDbContext context) : ViewModelBase { + // A reference to the provided TodoItem private TodoItem? _todoItem; /// - /// Creates a new ToDoItemViewModel for the given + /// Creates a new ToDoItemViewModel for the given . /// /// The item to load - /// The which is the parent + /// The which is the parent /// The to use - public TodoItemViewModel(TodoItem item, TodoListViewModel parent, AppDbContext context) : this(parent, context) + public TodoItemViewModel(TodoItem item, IDialogBus dialogBus, AppDbContext context) : this(dialogBus, context) { - // Init the properties with the given values + // Init the properties with the given values. this._IsComplete = item.IsComplete; this._content = item.Content; this._todoItem = item; } - // NOTE: This property is made without source generator. Uncomment the line below to use the source generator + // NOTE: This property is made without source generator. Uncomment the line below to use the source generator. // [ObservableProperty] private bool _IsComplete; /// - /// Gets or sets the checked status of each item + /// Gets or sets the checked status of the item. /// public bool IsComplete { get { return this._IsComplete; } set { - // Stpre the old value in order to undo the changes, if the save operation failed + // Store the old value in order to undo the changes, if the save operation failed. bool oldValue = this._IsComplete; if (SetProperty(ref this._IsComplete, value)) { - // save the item in case the have an updated value + // save the item in case we have an updated value SaveIsChecked(value, oldValue); } } } - private async void SaveIsChecked(bool value, bool oldValue) + /// + /// Saves the new value to the database + /// + /// the new value + /// the old value + private async void SaveIsChecked(bool newValue, bool oldValue) { - await SaveIsCheckedAsync(value, oldValue); + await SaveIsCheckedAsync(newValue, oldValue); } - // a counter that can be used to track save requests. Only used to demonstrate an exception after every third - // save operation. + // a counter that can be used to track save requests. + // Only used to demonstrate an exception after every third save operation. int updateCounter = 0; + /// + /// + /// + /// the new value + /// the old value + /// the to use + /// If the item wasn't saved correctly + /// If the item to update wasn't found in the database. private async Task SaveIsCheckedAsync(bool newValue, bool oldValue, CancellationToken cancellationToken = default) { TodoItem? storedItem = null; @@ -88,7 +107,7 @@ private async Task SaveIsCheckedAsync(bool newValue, bool oldValue, Cancellation _ = await context.SaveChangesAsync(cancellationToken); // Show an info to the user - parent.ShowInfoAlert("Saved changes successfully"); + dialogBus.ShowInfoAlert("Saved changes successfully"); } else { @@ -98,23 +117,21 @@ private async Task SaveIsCheckedAsync(bool newValue, bool oldValue, Cancellation } catch (Exception ex) { - // Set the Property back to it's old value + // Set the Property back to it's old value in case of any exception. SetProperty(ref this._IsComplete, oldValue, nameof(IsComplete)); if (storedItem is not null) storedItem.IsComplete = oldValue; - parent.ShowErrorAlert(ex.Message); + dialogBus.ShowErrorAlert(ex.Message); } } - /// /// Gets or sets the content of the to-do item /// [ObservableProperty] private string? _content; /// - /// Gets a ToDoItem for this Item-ViewModel + /// Gets a for this Item-ViewModel /// - /// The ToDoItem public TodoItem GetToDoItem() { if (this._todoItem is not null) diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoListViewModel.cs b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoListViewModel.cs index 4ebbf529..1bd8b2e2 100644 --- a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoListViewModel.cs +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoListViewModel.cs @@ -12,18 +12,28 @@ namespace TodoApp.Avalonia.ViewModels; -public partial class TodoListViewModel(AppDbContext context) : ViewModelBase +/// +/// A ViewModel used to represent a list of s +/// +/// the to use +public partial class TodoListViewModel(AppDbContext context) : ViewModelBase, IDialogBus { + /// + /// Gets or sets if the data is currently being refreshed. + /// [ObservableProperty] private bool isRefreshing; + /// + /// Gets or sets a collection of s + /// [ObservableProperty] private ConcurrentObservableCollection items = []; // -- Adding new Items -- /// - /// This command is used to add a new Item to the List + /// This command is used to add a new Item to the /// [RelayCommand (CanExecute = nameof(CanAddItem))] private async Task AddItemAsync(CancellationToken cancellationToken) @@ -44,7 +54,7 @@ private async Task AddItemAsync(CancellationToken cancellationToken) // Add the item to the end of the list Items.Add(new TodoItemViewModel(addition, this, context)); - // Update the title field ready for next insertion. + // Clear the NewItemContent-property for next insertion. NewItemContent = string.Empty; } catch (Exception ex) @@ -61,28 +71,31 @@ private async Task AddItemAsync(CancellationToken cancellationToken) private string? _newItemContent; /// - /// Returns if a new Item can be added. We require to have the NewItem some Text + /// Returns true if a new Item can be added. We require to have the NewItem some text. /// private bool CanAddItem() => !string.IsNullOrWhiteSpace(NewItemContent); // -- Removing Items -- /// - /// Removes the given Item from the list + /// This command removes the given Item from the -list /// /// the item to remove [RelayCommand] private async Task RemoveItemAsync(TodoItemViewModel item) { - // Remove the given item from the list - Items.Remove(item); - - // Remove it also from the data base + // Remove the item from the database _ = context.TodoItems.Remove(item.GetToDoItem()); _ = await context.SaveChangesAsync(); + + // Remove the given item from the list + Items.Remove(item); } + /// + /// This command is used to refresh the entire -list. + /// [RelayCommand] public async Task RefreshItemsAsync(CancellationToken cancellationToken = default) { @@ -97,6 +110,8 @@ public async Task RefreshItemsAsync(CancellationToken cancellationToken = defaul // Replace the items in the collection Items.Clear(); _ = Items.AddRange(dbItems.Select(x => new TodoItemViewModel(x, this, context))); + + this.ShowSuccessAlert("All Items loaded"); } catch (Exception ex) { diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Views/MainView.axaml b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Views/MainView.axaml index 6e3b60bb..17fe988a 100644 --- a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Views/MainView.axaml +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Views/MainView.axaml @@ -1,38 +1,48 @@ - + xmlns:vm="clr-namespace:TodoApp.Avalonia.ViewModels" + d:DesignWidth="500" + d:DesignHeight="450" + services:DialogManager.Register="{Binding }" + Background="Transparent" + Focusable="True" + Design.DataContext="{x:Static vm:DesignTimeViewModels.TodoListDesignerViewModel}" + x:DataType="vm:TodoListViewModel" + mc:Ignorable="d"> - + + - + - - - + - + @@ -55,16 +65,16 @@ Watermark="Add a new Item"> - + - - \ No newline at end of file diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Views/MainView.axaml.cs b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Views/MainView.axaml.cs index b753f613..b9981524 100644 --- a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Views/MainView.axaml.cs +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Views/MainView.axaml.cs @@ -1,11 +1,48 @@ +using System; +using Avalonia; using Avalonia.Controls; +using Avalonia.Controls.Notifications; +using Avalonia.Controls.Platform; +using Avalonia.Interactivity; +using TodoApp.Avalonia.Services; namespace TodoApp.Avalonia.Views; -public partial class MainView : UserControl +public partial class MainView : UserControl, INotificationService { public MainView() { InitializeComponent(); } + + /// + public WindowNotificationManager NotificationManager => this.WindowNotificationManager; + + protected override void OnLoaded(RoutedEventArgs e) + { + base.OnLoaded(e); + + // Configure the view to handle soft-keyboard appearance. This needs to happen after control is loaded. + // See: https://docs.avaloniaui.net/docs/concepts/services/input-pane + IInputPane? inputPane = TopLevel.GetTopLevel(this)?.InputPane; + + if (inputPane != null) + { + inputPane.StateChanged += InputPaneOnStateChanged; + } + } + + /// + /// This method is being called whenever an is opened or closed + /// + private void InputPaneOnStateChanged(object? sender, InputPaneStateEventArgs e) + { + // We need to add a Padding to the bottom where the sof InputPane will occupy our App. + // Note: There may be more things to consider, like different rotations and Keyboard positions. + double bottomPadding = e.NewState == InputPaneState.Open + ? Math.Max(Bounds.Height - e.EndRect.Top, 0) + : 0; + + this.Padding = new Thickness(0, 0, 0, bottomPadding); + } } \ No newline at end of file diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Views/MainWindow.axaml b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Views/MainWindow.axaml index 353cc5fe..c2edfce3 100644 --- a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Views/MainWindow.axaml +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Views/MainWindow.axaml @@ -8,7 +8,7 @@ Width="450" Height="800" x:Class="TodoApp.Avalonia.Views.MainWindow" Icon="/Assets/avalonia-logo.ico" - Design.DataContext="{x:Static vm:DesingTimeViewModels.TodoListDesignerViewModel}" + Design.DataContext="{x:Static vm:DesignTimeViewModels.TodoListDesignerViewModel}" Title="TodoApp.Avalonia"> From a00bfed947c30b95a4d71c8f1520d5d47b03bec9 Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 28 Nov 2024 16:47:08 +0100 Subject: [PATCH 11/13] Add sample screenshot to the docs --- .../todoapp/assets/TodoApp.Avalonia.Desktop.png | Bin 0 -> 18458 bytes docs/content/samples/todoapp/avalonia.md | 6 +++++- 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 docs/content/samples/todoapp/assets/TodoApp.Avalonia.Desktop.png diff --git a/docs/content/samples/todoapp/assets/TodoApp.Avalonia.Desktop.png b/docs/content/samples/todoapp/assets/TodoApp.Avalonia.Desktop.png new file mode 100644 index 0000000000000000000000000000000000000000..1e281c0d9d77b76c366c0ab17eb4693ecf3dfdbc GIT binary patch literal 18458 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 [!NOTE] > If you bump into issues at this point, please visit [Avalonia.Docs](https://docs.avaloniaui.net) and [Avalonia.Samples](https://github.com/AvaloniaUI/Avalonia.Samples) for some basic getting-started tutorials. +This is how the sample will look like: +![Avalonia sample on Desktop](assets/TodoApp.Avalonia.Desktop.png) + + ## Deploy a datasync server to Azure Before you begin adjusting the application for offline usage, you must [deploy a datasync service](../server.md). Make a note of the URI of the service before continuing. From c5c2620565a433eb99ac4c41924860fac3a4ad1b Mon Sep 17 00:00:00 2001 From: timunie Date: Sun, 8 Dec 2024 00:16:20 +0100 Subject: [PATCH 12/13] use nuget instead of project reference --- .../TodoApp.Avalonia/TodoApp.Avalonia.csproj | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/TodoApp.Avalonia.csproj b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/TodoApp.Avalonia.csproj index 22022179..adfa69b2 100644 --- a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/TodoApp.Avalonia.csproj +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/TodoApp.Avalonia.csproj @@ -16,10 +16,8 @@ + - - - - + From 7ba4401ca2a4b4d17e33eb8912f9748c9816f9aa Mon Sep 17 00:00:00 2001 From: Tim Date: Mon, 9 Dec 2024 17:03:13 +0100 Subject: [PATCH 13/13] Try fixing review - Added LoggingHandler - Renamed `TodoItem.Content` -> `TodoItem.Title` to match running DataSync-server --- .../TodoApp.Avalonia/Database/AppDbContext.cs | 19 ++++++-- .../TodoApp.Avalonia/Database/ToDoItem.cs | 2 +- .../Services/LoggingHandler.cs | 45 +++++++++++++++++++ .../ViewModels/TodoItemViewModel.cs | 10 ++--- .../ViewModels/TodoListViewModel.cs | 2 +- .../TodoApp.Avalonia/Views/MainView.axaml | 2 +- 6 files changed, 68 insertions(+), 12 deletions(-) create mode 100644 samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Services/LoggingHandler.cs diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/AppDbContext.cs b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/AppDbContext.cs index 8bf96c85..afd1f389 100644 --- a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/AppDbContext.cs +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/AppDbContext.cs @@ -1,15 +1,20 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System; +using System.Linq; using System.Threading; using System.Threading.Tasks; +using CommunityToolkit.Datasync.Client.Http; +using CommunityToolkit.Datasync.Client.Offline; using Microsoft.EntityFrameworkCore; +using TodoApp.Avalonia.Services; namespace TodoApp.Avalonia.Database; public class AppDbContext(DbContextOptions options) : DbContext(options) +// public class AppDbContext(DbContextOptions options) : OfflineDbContext(options) { public DbSet TodoItems => Set(); @@ -43,10 +48,16 @@ public async Task SynchronizeAsync(CancellationToken cancellationToken = default /// internal async Task AddSampleDataAsync(CancellationToken cancellationToken = default) { + // If there are already some items, don't add sample data + if (await TodoItems.AnyAsync(cancellationToken: cancellationToken)) + { + return; + } + await TodoItems.AddRangeAsync( - new TodoItem() { Id = Guid.NewGuid().ToString("N"), Content = """Say "Hello" to DataSync and Avalonia""" , IsComplete = true }, - new TodoItem() { Id = Guid.NewGuid().ToString("N"), Content = "Learn DataSync", IsComplete = false }, - new TodoItem() { Id = Guid.NewGuid().ToString("N"), Content = "Learn Avalonia", IsComplete = false }); + new TodoItem() { Id = Guid.NewGuid().ToString("N"), Title = """Say "Hello" to DataSync and Avalonia""" , IsComplete = true }, + new TodoItem() { Id = Guid.NewGuid().ToString("N"), Title = "Learn DataSync", IsComplete = false }, + new TodoItem() { Id = Guid.NewGuid().ToString("N"), Title = "Learn Avalonia", IsComplete = false }); await SaveChangesAsync(cancellationToken); } diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/ToDoItem.cs b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/ToDoItem.cs index 32d6032f..fa3204e0 100644 --- a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/ToDoItem.cs +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Database/ToDoItem.cs @@ -9,7 +9,7 @@ public class TodoItem : OfflineClientEntity /// /// Gets or sets the content. /// - public string Content { get; set; } = string.Empty; + public string Title { get; set; } = string.Empty; /// /// Gets or sets if the task was completed. diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Services/LoggingHandler.cs b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Services/LoggingHandler.cs new file mode 100644 index 00000000..971ee140 --- /dev/null +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Services/LoggingHandler.cs @@ -0,0 +1,45 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; + +namespace TodoApp.Avalonia.Services; + +/// +/// A delegating handler that logs the request/response to stdout. +/// +public class LoggingHandler : DelegatingHandler +{ + public LoggingHandler() : base() + { + } + + public LoggingHandler(HttpMessageHandler innerHandler) : base(innerHandler) + { + } + + protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + { + Debug.WriteLine($"[HTTP] >>> {request.Method} {request.RequestUri}"); + await WriteContentAsync(request.Content, cancellationToken); + + HttpResponseMessage response = await base.SendAsync(request, cancellationToken); + + Debug.WriteLine($"[HTTP] <<< {response.StatusCode} {response.ReasonPhrase}"); + await WriteContentAsync(response.Content, cancellationToken); + + return response; + } + + private static async Task WriteContentAsync(HttpContent content, CancellationToken cancellationToken = default) + { + if (content != null) + { + Debug.WriteLine($"[HTTP] >>> {await content.ReadAsStringAsync(cancellationToken)}"); + } + } +} diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoItemViewModel.cs b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoItemViewModel.cs index 84104d0a..446ef7ab 100644 --- a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoItemViewModel.cs +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoItemViewModel.cs @@ -32,7 +32,7 @@ public TodoItemViewModel(TodoItem item, IDialogBus dialogBus, AppDbContext conte { // Init the properties with the given values. this._IsComplete = item.IsComplete; - this._content = item.Content; + this._title = item.Title; this._todoItem = item; } @@ -125,9 +125,9 @@ private async Task SaveIsCheckedAsync(bool newValue, bool oldValue, Cancellation } /// - /// Gets or sets the content of the to-do item + /// Gets or sets the Title of the to-do item /// - [ObservableProperty] private string? _content; + [ObservableProperty] private string? _title; /// /// Gets a for this Item-ViewModel @@ -136,7 +136,7 @@ public TodoItem GetToDoItem() { if (this._todoItem is not null) { - this._todoItem.Content = Content ?? string.Empty; + this._todoItem.Title = Title ?? string.Empty; this._todoItem.IsComplete = IsComplete; return this._todoItem; } @@ -145,7 +145,7 @@ public TodoItem GetToDoItem() return new TodoItem() { IsComplete = this.IsComplete, - Content = this.Content ?? string.Empty + Title = this.Title ?? string.Empty }; } } \ No newline at end of file diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoListViewModel.cs b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoListViewModel.cs index 1bd8b2e2..2ff98da2 100644 --- a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoListViewModel.cs +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/ViewModels/TodoListViewModel.cs @@ -44,7 +44,7 @@ private async Task AddItemAsync(CancellationToken cancellationToken) TodoItem addition = new() { Id = Guid.NewGuid().ToString("N"), - Content = NewItemContent ?? throw new InvalidOperationException("New item content may not be null or empty") + Title = NewItemContent ?? throw new InvalidOperationException("New item content may not be null or empty") }; // Add the item to the database diff --git a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Views/MainView.axaml b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Views/MainView.axaml index 17fe988a..86ffb4ce 100644 --- a/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Views/MainView.axaml +++ b/samples/todoapp/TodoApp.Avalonia/TodoApp.Avalonia/Views/MainView.axaml @@ -41,7 +41,7 @@ -