diff --git a/.gitignore b/.gitignore
index 5801cb8..1bb6dff 100644
--- a/.gitignore
+++ b/.gitignore
@@ -81,4 +81,11 @@ Android/app/*.aab
Android/app/*.apk
Android/*.jks
Android/*.keystore
-Android/app/google-services.json
\ No newline at end of file
+Android/app/google-services.json
+
+# Dotnet
+
+Dotnet/.idea
+Dotnet/.vscode
+Dotnet/bin
+Dotnet/obj
diff --git a/Dotnet/App.xaml b/Dotnet/App.xaml
new file mode 100644
index 0000000..6f61e51
--- /dev/null
+++ b/Dotnet/App.xaml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Dotnet/App.xaml.cs b/Dotnet/App.xaml.cs
new file mode 100644
index 0000000..ec0df5a
--- /dev/null
+++ b/Dotnet/App.xaml.cs
@@ -0,0 +1,14 @@
+namespace Guides;
+
+public partial class App : Application
+{
+ public App()
+ {
+ InitializeComponent();
+ }
+
+ protected override Window CreateWindow(IActivationState? activationState)
+ {
+ return new Window(new AppShell());
+ }
+}
\ No newline at end of file
diff --git a/Dotnet/AppShell.xaml b/Dotnet/AppShell.xaml
new file mode 100644
index 0000000..02e22ba
--- /dev/null
+++ b/Dotnet/AppShell.xaml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
diff --git a/Dotnet/AppShell.xaml.cs b/Dotnet/AppShell.xaml.cs
new file mode 100644
index 0000000..43b3549
--- /dev/null
+++ b/Dotnet/AppShell.xaml.cs
@@ -0,0 +1,9 @@
+namespace Guides;
+
+public partial class AppShell : Shell
+{
+ public AppShell()
+ {
+ InitializeComponent();
+ }
+}
\ No newline at end of file
diff --git a/Dotnet/Converters/IsZeroConverter.cs b/Dotnet/Converters/IsZeroConverter.cs
new file mode 100644
index 0000000..4cf752d
--- /dev/null
+++ b/Dotnet/Converters/IsZeroConverter.cs
@@ -0,0 +1,20 @@
+using System.Globalization;
+
+namespace Guides.Converters;
+
+public class IsZeroConverter : IValueConverter
+{
+ public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
+ {
+ if (value is int count)
+ {
+ return count == 0;
+ }
+ return false;
+ }
+
+ public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+}
\ No newline at end of file
diff --git a/Dotnet/Converters/ListToStringConverter.cs b/Dotnet/Converters/ListToStringConverter.cs
new file mode 100644
index 0000000..8ce67fa
--- /dev/null
+++ b/Dotnet/Converters/ListToStringConverter.cs
@@ -0,0 +1,20 @@
+using System.Globalization;
+
+namespace Guides.Converters;
+
+public class ListToStringConverter : IValueConverter
+{
+ public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
+ {
+ if (value is List list)
+ {
+ return string.Join(", ", list);
+ }
+ return string.Empty;
+ }
+
+ public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+}
\ No newline at end of file
diff --git a/Dotnet/Converters/NotNullConverter.cs b/Dotnet/Converters/NotNullConverter.cs
new file mode 100644
index 0000000..fcf5702
--- /dev/null
+++ b/Dotnet/Converters/NotNullConverter.cs
@@ -0,0 +1,16 @@
+using System.Globalization;
+
+namespace Guides.Converters;
+
+public class NotNullConverter : IValueConverter
+{
+ public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
+ {
+ return value != null;
+ }
+
+ public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+}
\ No newline at end of file
diff --git a/Dotnet/Converters/NotZeroConverter.cs b/Dotnet/Converters/NotZeroConverter.cs
new file mode 100644
index 0000000..4abf9b2
--- /dev/null
+++ b/Dotnet/Converters/NotZeroConverter.cs
@@ -0,0 +1,20 @@
+using System.Globalization;
+
+namespace Guides.Converters;
+
+public class NotZeroConverter : IValueConverter
+{
+ public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
+ {
+ if (value is int count)
+ {
+ return count > 0;
+ }
+ return true;
+ }
+
+ public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+}
\ No newline at end of file
diff --git a/Dotnet/Guides.csproj b/Dotnet/Guides.csproj
new file mode 100644
index 0000000..4f292d2
--- /dev/null
+++ b/Dotnet/Guides.csproj
@@ -0,0 +1,99 @@
+
+
+
+
+
+ net9.0-android;net9.0-ios;
+
+
+
+
+ Exe
+ Guides
+ true
+ true
+ enable
+ enable
+
+
+ Guides
+
+
+ com.companyname.guides
+
+
+ 1.0
+ 1
+
+
+ None
+
+ 15.0
+
+
+ 26.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Designer
+
+
+
+
+
+ MainPage.xaml
+ Code
+
+
+
+
+
+ dittoConfig.json
+ PreserveNewest
+
+
+
+
diff --git a/Dotnet/Guides.sln b/Dotnet/Guides.sln
new file mode 100644
index 0000000..b51b651
--- /dev/null
+++ b/Dotnet/Guides.sln
@@ -0,0 +1,16 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Guides", "Guides.csproj", "{897A2B3F-166A-46B9-884D-BDAAC7A6A2EE}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {897A2B3F-166A-46B9-884D-BDAAC7A6A2EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {897A2B3F-166A-46B9-884D-BDAAC7A6A2EE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {897A2B3F-166A-46B9-884D-BDAAC7A6A2EE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {897A2B3F-166A-46B9-884D-BDAAC7A6A2EE}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+EndGlobal
diff --git a/Dotnet/Guides.sln.DotSettings.user b/Dotnet/Guides.sln.DotSettings.user
new file mode 100644
index 0000000..1c1b501
--- /dev/null
+++ b/Dotnet/Guides.sln.DotSettings.user
@@ -0,0 +1,2 @@
+
+ ForceIncluded
\ No newline at end of file
diff --git a/Dotnet/MauiProgram.cs b/Dotnet/MauiProgram.cs
new file mode 100644
index 0000000..a3b3807
--- /dev/null
+++ b/Dotnet/MauiProgram.cs
@@ -0,0 +1,52 @@
+using System.Text.Json;
+using Guides.Models;
+using Guides.Services;
+using Guides.ViewModels;
+using Guides.Views;
+using Microsoft.Extensions.Logging;
+using Syncfusion.Maui.Toolkit.Hosting;
+
+namespace Guides;
+
+public static class MauiProgram
+{
+ private static readonly JsonSerializerOptions JsonSerializerOptions = new JsonSerializerOptions
+ { PropertyNameCaseInsensitive = true };
+
+ public static MauiApp CreateMauiApp()
+ {
+ var builder = MauiApp.CreateBuilder();
+ builder
+ .UseMauiApp()
+ // Initialize the Syncfusion .NET MAUI Toolkit by adding the below line of code
+ .ConfigureSyncfusionToolkit()
+ // Initialize the Fonts
+ .ConfigureFonts(fonts =>
+ {
+ fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
+ fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
+ });
+
+ // Register services
+ builder.Services.AddSingleton(serviceProvider =>
+ {
+ // Load config synchronously
+ using var stream = FileSystem.Current.OpenAppPackageFileAsync("dittoConfig.json").Result;
+ using var reader = new StreamReader(stream);
+ var fileContent = reader.ReadToEndAsync().Result;
+ var config = JsonSerializer.Deserialize(fileContent, JsonSerializerOptions);
+ return config ?? new AppConfig("", "", "");
+ });
+
+ //register Services and ViewModels
+ builder.Services.AddSingleton();
+ builder.Services.AddSingleton();
+ builder.Services.AddTransient();
+
+#if DEBUG
+ builder.Logging.AddDebug();
+#endif
+
+ return builder.Build();
+ }
+}
\ No newline at end of file
diff --git a/Dotnet/Models/AppConfig.cs b/Dotnet/Models/AppConfig.cs
new file mode 100644
index 0000000..fba4f83
--- /dev/null
+++ b/Dotnet/Models/AppConfig.cs
@@ -0,0 +1,8 @@
+using System.Text.Json.Serialization;
+
+namespace Guides.Models;
+
+public record AppConfig(
+ [property: JsonPropertyName("appId")] string AppId,
+ [property: JsonPropertyName("authToken")] string AuthToken,
+ [property: JsonPropertyName("endpointUrl")] string EndpointUrl);
\ No newline at end of file
diff --git a/Dotnet/Models/Planet.cs b/Dotnet/Models/Planet.cs
new file mode 100644
index 0000000..776fe88
--- /dev/null
+++ b/Dotnet/Models/Planet.cs
@@ -0,0 +1,130 @@
+using System.Text.Json.Serialization;
+using CommunityToolkit.Mvvm.ComponentModel;
+
+namespace Guides.Models;
+
+public partial class Planet
+ : ObservableObject
+{
+ [ObservableProperty]
+ [property: JsonPropertyName("_id")]
+ string id;
+
+ [ObservableProperty]
+ [property: JsonPropertyName("hasRings")]
+ bool hasRings;
+
+ [ObservableProperty]
+ [property: JsonPropertyName("isArchived")]
+ bool isArchived;
+
+ [ObservableProperty]
+ [property: JsonPropertyName("mainAtmosphere")]
+ List mainAtmosphere;
+
+ [ObservableProperty]
+ [property: JsonPropertyName("name")]
+ string name;
+
+ [ObservableProperty]
+ [property: JsonPropertyName("orderFromSun")]
+ int orderFromSun;
+
+ [ObservableProperty]
+ [property: JsonPropertyName("planetId")]
+ string planetId;
+
+ [ObservableProperty]
+ [property: JsonPropertyName("surfaceTemperatureC")]
+ private Temperature surfaceTemperatureC;
+
+ public Planet(string id,
+ bool hasRings,
+ bool isArchived,
+ List mainAtmosphere,
+ string name,
+ int orderFromSun,
+ string planetId,
+ Temperature surfaceTemperatureC)
+ {
+ Id = id;
+ HasRings = hasRings;
+ IsArchived = isArchived;
+ MainAtmosphere = mainAtmosphere;
+ Name = name;
+ OrderFromSun = orderFromSun;
+ PlanetId = planetId;
+ SurfaceTemperatureC = surfaceTemperatureC;
+ }
+
+ public Dictionary ToDictionary()
+ {
+ return new Dictionary
+ {
+ { "_id", Id },
+ { "hasRings", HasRings },
+ { "isArchived", IsArchived },
+ { "mainAtmosphere", MainAtmosphere },
+ { "name", Name },
+ { "orderFromSun", OrderFromSun },
+ { "planetId", PlanetId },
+ { "surfaceTemperatureC", SurfaceTemperatureC.ToDictionary() }
+ };
+ }
+
+ public static Planet FromDictionary(Dictionary value)
+ {
+ return new Planet(
+ id: value["_id"]?.ToString() ?? string.Empty,
+ hasRings: Convert.ToBoolean(value["hasRings"]),
+ isArchived: Convert.ToBoolean(value["isArchived"]),
+ mainAtmosphere: ((value["mainAtmosphere"] as List