diff --git a/Vanara-Jnana/App.xaml.cs b/Vanara-Jnana/App.xaml.cs
index 16fe5c1c..dbbb27c7 100644
--- a/Vanara-Jnana/App.xaml.cs
+++ b/Vanara-Jnana/App.xaml.cs
@@ -1,3 +1,4 @@
+using Jnana;
using Microsoft.UI.Windowing;
using Microsoft.UI.Xaml;
//using LaunchActivatedEventArgs = Windows.ApplicationModel.Activation.LaunchActivatedEventArgs;
diff --git a/Vanara-Jnana/Assets/Vanara/dahall-NuGet Avatar.png b/Vanara-Jnana/Assets/Vanara/dahall-NuGet Avatar.png
new file mode 100644
index 00000000..f04a0b92
Binary files /dev/null and b/Vanara-Jnana/Assets/Vanara/dahall-NuGet Avatar.png differ
diff --git a/Vanara-Jnana/Directory.Packages.props b/Vanara-Jnana/Directory.Packages.props
index d915cf5f..c7226e90 100644
--- a/Vanara-Jnana/Directory.Packages.props
+++ b/Vanara-Jnana/Directory.Packages.props
@@ -1,6 +1,5 @@
-
diff --git a/Vanara-Jnana/Helpers/ImageExtensions.cs b/Vanara-Jnana/Helpers/ImageExtensions.cs
new file mode 100644
index 00000000..9452ed3b
--- /dev/null
+++ b/Vanara-Jnana/Helpers/ImageExtensions.cs
@@ -0,0 +1,25 @@
+using Microsoft.UI.Xaml.Media.Imaging;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Jnana.Helpers;
+
+public class ImageExtensions
+{
+ public static BitmapImage? ToBitmapImage(byte[]? bytes)
+ {
+ if (bytes == null || bytes.Length == 0)
+ return null;
+
+ var bitmap = new BitmapImage();
+
+ using var ms = new MemoryStream(bytes);
+ var ras = ms.AsRandomAccessStream();
+
+ bitmap.SetSource(ras);
+ return bitmap;
+ }
+}
diff --git a/Vanara-Jnana/Helpers/WindowsSystemDispatcherQueueHelper.cs b/Vanara-Jnana/Helpers/WindowsSystemDispatcherQueueHelper.cs
index 7e7023c7..5f93150a 100644
--- a/Vanara-Jnana/Helpers/WindowsSystemDispatcherQueueHelper.cs
+++ b/Vanara-Jnana/Helpers/WindowsSystemDispatcherQueueHelper.cs
@@ -1,6 +1,6 @@
using Microsoft.UI.Dispatching;
-namespace ClassicSamplesBrowser.Helpers;
+namespace Jnana.Helpers;
public class WindowsSystemDispatcherQueueHelper
{
diff --git a/Vanara-Jnana/Jnana.csproj b/Vanara-Jnana/Jnana.csproj
index 520e6023..107897eb 100644
--- a/Vanara-Jnana/Jnana.csproj
+++ b/Vanara-Jnana/Jnana.csproj
@@ -26,9 +26,19 @@
+
+
-
-
+
+
+
+
+
+
+
+
+
+
diff --git a/Vanara-Jnana/MainWindow.xaml b/Vanara-Jnana/MainWindow.xaml
index 87402db4..0fec0fbe 100644
--- a/Vanara-Jnana/MainWindow.xaml
+++ b/Vanara-Jnana/MainWindow.xaml
@@ -1,9 +1,8 @@
diff --git a/Vanara-Jnana/MainWindow.xaml.cs b/Vanara-Jnana/MainWindow.xaml.cs
index f66ed72b..8eea1a8d 100644
--- a/Vanara-Jnana/MainWindow.xaml.cs
+++ b/Vanara-Jnana/MainWindow.xaml.cs
@@ -1,17 +1,15 @@
-using ClassicSamplesBrowser.Helpers;
-using ClassicSamplesBrowser.Views;
+using Jnana.Views;
using Microsoft.UI.Composition.SystemBackdrops;
using Microsoft.UI.Windowing;
using Microsoft.UI.Xaml;
using Microsoft.UI;
-using System.Drawing;
+using System.Diagnostics;
using Vanara.PInvoke;
using Windows.Graphics;
using WinRT;
-using ClassicSamplesBrowser.Services;
-using System.Diagnostics;
+using Jnana.Helpers;
-namespace ClassicSamplesBrowser;
+namespace Jnana;
public sealed partial class MainWindow : Window
{
@@ -28,8 +26,8 @@ public MainWindow()
// _navigationService = new NavigationService(RootFrame);
- //var initialSize = ApplicationData.Current.LocalSettings.Values["InitialWindowSize"] as string;
- //this.AppWindow.Size = _initialWindowSize;
+ // var initialSize = ApplicationData.Current.LocalSettings.Values["InitialWindowSize"] as string;
+ // this.AppWindow.Size = _initialWindowSize;
// AppWindow.Size = new Size() { Width = 800, Height = 600 };
_ = RootFrame.Navigate(typeof(ShellPage));
diff --git a/Vanara-Jnana/Models/ApiAssemblyModel.cs b/Vanara-Jnana/Models/ApiAssemblyModel.cs
deleted file mode 100644
index 12e786ba..00000000
--- a/Vanara-Jnana/Models/ApiAssemblyModel.cs
+++ /dev/null
@@ -1,5 +0,0 @@
-namespace ClassicSamplesBrowser.Models;
-
-internal class ApiAssemblyModel
-{
-}
\ No newline at end of file
diff --git a/Vanara-Jnana/Models/ApiEnumModel.cs b/Vanara-Jnana/Models/ApiEnumModel.cs
deleted file mode 100644
index b3fd6f9b..00000000
--- a/Vanara-Jnana/Models/ApiEnumModel.cs
+++ /dev/null
@@ -1,5 +0,0 @@
-namespace ClassicSamplesBrowser.Models;
-
-internal class ApiEnumModel
-{
-}
\ No newline at end of file
diff --git a/Vanara-Jnana/Models/ApiMethodModel.cs b/Vanara-Jnana/Models/ApiMethodModel.cs
deleted file mode 100644
index e7f45188..00000000
--- a/Vanara-Jnana/Models/ApiMethodModel.cs
+++ /dev/null
@@ -1,5 +0,0 @@
-namespace ClassicSamplesBrowser.Models;
-
-internal class ApiMethodModel
-{
-}
\ No newline at end of file
diff --git a/Vanara-Jnana/Models/ApiNamespaceModel.cs b/Vanara-Jnana/Models/ApiNamespaceModel.cs
deleted file mode 100644
index 6c0e2e09..00000000
--- a/Vanara-Jnana/Models/ApiNamespaceModel.cs
+++ /dev/null
@@ -1,5 +0,0 @@
-namespace ClassicSamplesBrowser.Models;
-
-internal class ApiNamespaceModel
-{
-}
\ No newline at end of file
diff --git a/Vanara-Jnana/Models/ApiPropertyModel.cs b/Vanara-Jnana/Models/ApiPropertyModel.cs
deleted file mode 100644
index bc91c5d7..00000000
--- a/Vanara-Jnana/Models/ApiPropertyModel.cs
+++ /dev/null
@@ -1,5 +0,0 @@
-namespace ClassicSamplesBrowser.Models;
-
-internal class ApiPropertyModel
-{
-}
\ No newline at end of file
diff --git a/Vanara-Jnana/Models/ApiSampleModel.cs b/Vanara-Jnana/Models/ApiSampleModel.cs
deleted file mode 100644
index 650c7826..00000000
--- a/Vanara-Jnana/Models/ApiSampleModel.cs
+++ /dev/null
@@ -1,5 +0,0 @@
-namespace ClassicSamplesBrowser.Models;
-
-internal class ApiSampleModel
-{
-}
\ No newline at end of file
diff --git a/Vanara-Jnana/Models/ApiTypeModel.cs b/Vanara-Jnana/Models/ApiTypeModel.cs
deleted file mode 100644
index 5bdd927b..00000000
--- a/Vanara-Jnana/Models/ApiTypeModel.cs
+++ /dev/null
@@ -1,5 +0,0 @@
-namespace ClassicSamplesBrowser.Models;
-
-internal class ApiTypeModel
-{
-}
\ No newline at end of file
diff --git a/Vanara-Jnana/Models/INavigationService.cs b/Vanara-Jnana/Models/INavigationService.cs
new file mode 100644
index 00000000..984546f1
--- /dev/null
+++ b/Vanara-Jnana/Models/INavigationService.cs
@@ -0,0 +1,23 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Jnana.Models;
+
+public interface INavigationService
+{
+ public enum Area
+ {
+ Void,
+ NuGets,
+ GitHub,
+ Samples,
+ Disassembler,
+ Utilities,
+ Settings
+ }
+
+ void NavigateTo(Area area);
+}
diff --git a/Vanara-Jnana/Services/ISettingsSerializer.cs b/Vanara-Jnana/Models/ISettingsSerializer.cs
similarity index 84%
rename from Vanara-Jnana/Services/ISettingsSerializer.cs
rename to Vanara-Jnana/Models/ISettingsSerializer.cs
index 852b0637..756fe96b 100644
--- a/Vanara-Jnana/Services/ISettingsSerializer.cs
+++ b/Vanara-Jnana/Models/ISettingsSerializer.cs
@@ -1,6 +1,6 @@
using System.ComponentModel;
-namespace ClassicSamplesBrowser.Services;
+namespace Jnana.Models;
public interface ISettingsSerializer : INotifyPropertyChanged
{
diff --git a/Vanara-Jnana/Services/INuGetCatalogService.cs b/Vanara-Jnana/Services/INuGetCatalogService.cs
new file mode 100644
index 00000000..3b0e13c8
--- /dev/null
+++ b/Vanara-Jnana/Services/INuGetCatalogService.cs
@@ -0,0 +1,36 @@
+using Microsoft.UI.Xaml.Media.Imaging;
+using NuGet.Versioning;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Jnana.Services;
+
+public record PackageId(string Id);
+
+public record PackageVersionInfo(
+ string Id,
+ string Version,
+ Uri? IconUrl,
+ string? Description,
+ string? Summary,
+ BitmapImage? Icon
+);
+
+public record PackageContent(
+ string Id,
+ NuGetVersion Version,
+ IReadOnlyList Assemblies,
+ string? Readme,
+ byte[]? IconBytes,
+ BitmapImage? Icon
+);
+
+public interface INuGetCatalogService
+{
+ IAsyncEnumerable SearchPackagesAsync(string prefix, CancellationToken token);
+ Task GetLatestStableVersionAsync(string packageId, CancellationToken token);
+ Task DownloadPackageAsync(string id, NuGetVersion version, CancellationToken token);
+}
diff --git a/Vanara-Jnana/Services/NavigationService.cs b/Vanara-Jnana/Services/NavigationService.cs
index 27e97594..de9e4e5a 100644
--- a/Vanara-Jnana/Services/NavigationService.cs
+++ b/Vanara-Jnana/Services/NavigationService.cs
@@ -1,125 +1,51 @@
-using ClassicSamplesBrowser.Views;
-using CommunityToolkit.Mvvm.ComponentModel;
+using CommunityToolkit.Mvvm.ComponentModel;
+using Jnana.Models;
using Jnana.Views;
using Microsoft.UI.Xaml.Controls;
-using Microsoft.Win32;
using System.Diagnostics;
-using Vanara.PInvoke;
-using static ClassicSamplesBrowser.Services.INavigationService;
+using static Jnana.Models.INavigationService;
-namespace ClassicSamplesBrowser.Services;
-
-public interface INavigationService
-{
- public enum Area
- {
- Void,
- NuGets,
- GitHub,
- Samples,
- Disassembler,
- Utilities,
- Settings
- }
-
- void NavigateTo(Area area);
-}
+namespace Jnana.Services;
public partial class NavigationService : ObservableObject, INavigationService
{
- public Area CurrentArea
- {
- get;
- set
- {
- if (SetProperty(ref field, value))
- {
- OnPropertyChanged(nameof(CurrentPage));
- }
- }
- } = Area.Void;
-
- public Page CurrentPage => CurrentArea switch
- {
- Area.GitHub => new GitHubPage(),
- Area.NuGets => new NuGetsPage(),
- Area.Samples => new SamplesPage(),
- Area.Settings => new SettingsPage(),
- _ => new VoidPage()
- };
-
private readonly Frame _frame;
private readonly Dictionary _areaPageMap;
public NavigationService(Frame frame)
{
- _frame = frame;
+ _frame = frame ?? throw new ArgumentNullException(nameof(frame));
_areaPageMap = new()
{
+ { Area.Disassembler, typeof(DisassemblerPage) },
{ Area.GitHub, typeof(GitHubPage) },
{ Area.NuGets, typeof(NuGetsPage) },
{ Area.Samples, typeof(SamplesPage) },
{ Area.Settings, typeof(SettingsPage) },
+ { Area.Utilities, typeof(UtilitiesPage) },
{ Area.Void, typeof(VoidPage) },
};
-
- // INFO: @dahall - select a default page to navigate to on loading, to ensure the main content area is populated with a page, and to establish a consistent starting point for navigation
- //NavigateTo(Area.Void);
- //NavigateTo(Area.Settings);
}
- // // TODO:
- // // public static void Navigate(Shell32.IShellFolder shellFolder)
- // // {
- // // TryNavigate(shellFolder);
- // // }
- // public bool TryNavigate(object target, bool allowPageCreation = true)
- // {
- // try
- // {
- // var pageType = target switch
- // {
- // "Assemblies" => typeof(AssembliesPage),
- // "GitHub" => typeof(GitHubPage),
- // "NuGets" => typeof(NuGetsPage),
- // "Samples" => typeof(SamplesPage),
- // "Settings" => typeof(SettingsPage),
- // "Start" => typeof(StartPage),
- // "Utilities" => typeof(UtilitiesPage),
- // _ => null
- // };
- //
- // // Check if the page type is null and if page creation is allowed
- // if (pageType == null && !allowPageCreation)
- // {
- // //LogWriter.PrintLine("Page type is null and page creation is not allowed.");
- // return false;
- // }
- //
- // // TODO: _frame.Navigate(pageType ?? new UtilitiesPage());
- // //return _frame.Navigate(pageType);
- // return true;
- // }
- // catch (Exception ex)
- // {
- // Debug.Fail(ex.ToString());
- // throw;
- // }
- // }
-
- public static void NavigateBack() { }
-
- public static void Forward() { }
-
public void NavigateTo(Area area)
{
- if (_areaPageMap.TryGetValue(area, out var pageType))
+ try
+ {
+ if (_areaPageMap.TryGetValue(area, out var pageType))
+ {
+ Debug.Print($"Navigating to `{area}` page.");
+ _frame.Navigate(pageType);
+ }
+ else
+ {
+ Debug.Print($"Failed to get page for `{area}` from PageMap.");
+ }
+ }
+ catch (Exception ex)
{
- Debug.Print($"Navigating to `{area}` page.");
- _frame.Navigate(pageType);
+ Debug.Fail(ex.ToString());
+ throw;
}
}
-
- //public void Navigate(Area area) { CurrentArea = area; }
}
diff --git a/Vanara-Jnana/Services/NuGetCatalogDiskCache.cs b/Vanara-Jnana/Services/NuGetCatalogDiskCache.cs
new file mode 100644
index 00000000..83b8097d
--- /dev/null
+++ b/Vanara-Jnana/Services/NuGetCatalogDiskCache.cs
@@ -0,0 +1,105 @@
+using NuGet.Versioning;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using System.Text;
+using System.Text.Json;
+using System.Threading.Tasks;
+
+namespace Jnana.Services;
+
+public sealed class NuGetCatalogDiskCache : INuGetCatalogService
+{
+ private readonly INuGetCatalogService _inner;
+ private readonly string _cacheFile;
+ private readonly TimeSpan _ttl = TimeSpan.FromHours(24);
+
+ private Dictionary? _cache;
+ private DateTime _timestamp;
+
+ public NuGetCatalogDiskCache(INuGetCatalogService inner, string cacheFile)
+ {
+ _inner = inner;
+ _cacheFile = cacheFile;
+
+ _ = LoadFromDisk();
+ }
+
+ private async Task LoadFromDisk()
+ {
+ if (!File.Exists(_cacheFile))
+ return;
+
+ try
+ {
+ var json = File.ReadAllText(_cacheFile);
+ var data = JsonSerializer.Deserialize(json);
+
+ if (data != null && DateTime.UtcNow - data.Timestamp < _ttl)
+ {
+ _timestamp = data.Timestamp;
+ _cache = data.Packages.ToDictionary(p => p.Id, p => p);
+
+ Debug.WriteLine("LoadFromDisk(): Cache dated {0} successfully loaded from disk ", _timestamp);
+ }
+ }
+ catch
+ {
+ // we can ignore any errors here - if the cache is corrupted or unreadable, we'll just start fresh
+ }
+ }
+
+ private void SaveToDisk()
+ {
+ var data = new CacheData
+ {
+ Timestamp = DateTime.UtcNow,
+ Packages = _cache?.Values.ToList() ?? new()
+ };
+
+ var json = JsonSerializer.Serialize(data, new JsonSerializerOptions { WriteIndented = true });
+ Directory.CreateDirectory(Path.GetDirectoryName(_cacheFile)!);
+ File.WriteAllText(_cacheFile, json);
+ }
+
+ public async IAsyncEnumerable SearchPackagesAsync(
+ string prefix,
+ [EnumeratorCancellation] CancellationToken token)
+ {
+ await foreach (var pkg in _inner.SearchPackagesAsync(prefix, token))
+ yield return pkg;
+ }
+
+ public async Task GetLatestStableVersionAsync(
+ string packageId,
+ CancellationToken token)
+ {
+ _cache ??= new();
+
+ if (_cache.TryGetValue(packageId, out var info))
+ return info;
+
+ var latest = await _inner.GetLatestStableVersionAsync(packageId, token);
+ if (latest != null)
+ {
+ _cache[packageId] = latest;
+ SaveToDisk();
+ }
+
+ return latest;
+ }
+
+ public Task DownloadPackageAsync(
+ string id,
+ NuGetVersion version,
+ CancellationToken token)
+ => _inner.DownloadPackageAsync(id, version, token);
+
+ private sealed class CacheData
+ {
+ public DateTime Timestamp { get; set; }
+ public List Packages { get; set; } = new();
+ }
+}
diff --git a/Vanara-Jnana/Services/NuGetCatalogMemoryCache.cs b/Vanara-Jnana/Services/NuGetCatalogMemoryCache.cs
new file mode 100644
index 00000000..80302916
--- /dev/null
+++ b/Vanara-Jnana/Services/NuGetCatalogMemoryCache.cs
@@ -0,0 +1,49 @@
+using NuGet.Versioning;
+using System.Runtime.CompilerServices;
+
+namespace Jnana.Services;
+
+public sealed class NuGetCatalogMemoryCache : INuGetCatalogService
+{
+ private readonly INuGetCatalogService _inner;
+ private readonly TimeSpan _ttl = TimeSpan.FromHours(24);
+
+ private readonly Dictionary _cache
+ = new();
+
+ public NuGetCatalogMemoryCache(INuGetCatalogService inner)
+ {
+ _inner = inner;
+ }
+
+ public async IAsyncEnumerable SearchPackagesAsync(
+ string prefix,
+ [EnumeratorCancellation] CancellationToken token)
+ {
+ await foreach (var pkg in _inner.SearchPackagesAsync(prefix, token))
+ yield return pkg;
+ }
+
+ public async Task GetLatestStableVersionAsync(
+ string packageId,
+ CancellationToken token)
+ {
+ if (_cache.TryGetValue(packageId, out var entry))
+ {
+ if (DateTime.UtcNow - entry.Timestamp < _ttl)
+ return entry.Info;
+ }
+
+ var info = await _inner.GetLatestStableVersionAsync(packageId, token);
+ if (info != null)
+ _cache[packageId] = (DateTime.UtcNow, info);
+
+ return info;
+ }
+
+ public Task DownloadPackageAsync(
+ string id,
+ NuGetVersion version,
+ CancellationToken token)
+ => _inner.DownloadPackageAsync(id, version, token);
+}
diff --git a/Vanara-Jnana/Services/NuGetCatalogService.cs b/Vanara-Jnana/Services/NuGetCatalogService.cs
new file mode 100644
index 00000000..52f247bc
--- /dev/null
+++ b/Vanara-Jnana/Services/NuGetCatalogService.cs
@@ -0,0 +1,134 @@
+using Jnana.Helpers;
+using Microsoft.UI.Xaml.Media.Imaging;
+using NuGet.Common;
+using NuGet.Packaging;
+using NuGet.Protocol.Core.Types;
+using NuGet.Protocol;
+using NuGet.Versioning;
+using System.Runtime.CompilerServices;
+
+namespace Jnana.Services;
+
+public sealed class NuGetCatalogService : INuGetCatalogService
+{
+ private readonly SourceRepository _repo;
+ private readonly ILogger? _logger;
+
+ public NuGetCatalogService(string sourceUrl, ILogger? logger = null)
+ {
+ _repo = Repository.Factory.GetCoreV3(sourceUrl);
+ _logger = logger ?? NullLogger.Instance;
+ }
+
+ public async IAsyncEnumerable SearchPackagesAsync(
+ string prefix,
+ [EnumeratorCancellation] CancellationToken token)
+ {
+ var search = await _repo.GetResourceAsync(token);
+ var filter = new SearchFilter(includePrerelease: true);
+
+ // TODO: @dahall NuGet's search API doesn't support prefix searching, so we may fetch a bunch of results and then would have to filter them ourselves.
+ // TODO: See the results, they include `MonitoringUtils` and `LeadManager.Common`. Note these appear in VS NuGet Pane, too.
+ var results = await search.SearchAsync(prefix, filter, 0, 200, _logger, token);
+
+ foreach (var r in results)
+ yield return new PackageId(r.Identity.Id);
+ }
+
+ public async Task GetLatestStableVersionAsync(
+ string packageId,
+ CancellationToken token)
+ {
+ var search = await _repo.GetResourceAsync(token);
+ var filter = new SearchFilter(includePrerelease: true);
+
+ var results = await search.SearchAsync(packageId, filter, 0, 1, _logger, token);
+
+ var pkg = results.FirstOrDefault();
+ if (pkg is null)
+ return null;
+
+ var versions = await pkg.GetVersionsAsync();
+
+ var latestStable = versions
+ .Where(v => !v.Version.IsPrerelease)
+ .OrderBy(v => v.Version)
+ .LastOrDefault();
+
+ if (latestStable is null)
+ return null;
+
+ return new PackageVersionInfo(
+ pkg.Identity.Id,
+ latestStable.Version.ToString(),
+ pkg.IconUrl,
+ pkg.Description,
+ pkg.Summary,
+ Icon: null
+ );
+ }
+
+ public async Task DownloadPackageAsync(
+ string id,
+ NuGetVersion version,
+ CancellationToken token)
+ {
+ var find = await _repo.GetResourceAsync(token);
+
+ using var cache = new SourceCacheContext();
+ using var stream = new MemoryStream();
+
+ bool ok = await find.CopyNupkgToStreamAsync(
+ id, version, stream, cache, _logger, token);
+
+ if (!ok)
+ throw new InvalidOperationException($"Could not download {id} {version}");
+
+ stream.Position = 0;
+ using var reader = new PackageArchiveReader(stream);
+ var packageFiles = reader.GetFiles().ToList();
+
+ // First, extract all DLLs
+ var dlls = packageFiles
+ .Where(f => f.EndsWith(".dll", StringComparison.OrdinalIgnoreCase))
+ .ToList();
+
+ // Extract the readme if it exists
+ string? readmeText = null;
+ var readmePath = packageFiles.FirstOrDefault(f =>
+ f.EndsWith("readme.md", StringComparison.OrdinalIgnoreCase));
+
+ if (readmePath != null)
+ {
+ using var readmeStream = await reader.GetStreamAsync(readmePath, token);
+ using var sr = new StreamReader(readmeStream);
+ readmeText = await sr.ReadToEndAsync();
+ }
+
+ // Extract the icon if it exists
+ byte[]? iconBytes = null;
+ var iconPath = packageFiles.FirstOrDefault(f =>
+ f.EndsWith(".png", StringComparison.OrdinalIgnoreCase) ||
+ f.EndsWith(".jpg", StringComparison.OrdinalIgnoreCase));
+
+ BitmapImage? Icon = null;
+ if (iconPath != null)
+ {
+ using var iconStream = await reader.GetStreamAsync(iconPath, token);
+ using var ms = new MemoryStream();
+ await iconStream.CopyToAsync(ms, token);
+ iconBytes = ms.ToArray();
+
+ Icon = ImageExtensions.ToBitmapImage(iconBytes);
+ }
+
+ return new PackageContent(
+ id,
+ version,
+ dlls,
+ readmeText,
+ iconBytes,
+ Icon
+ );
+ }
+}
diff --git a/Vanara-Jnana/Services/TabNavigationService.cs b/Vanara-Jnana/Services/TabNavigationService.cs
index c48ad068..55559b3a 100644
--- a/Vanara-Jnana/Services/TabNavigationService.cs
+++ b/Vanara-Jnana/Services/TabNavigationService.cs
@@ -1,9 +1,7 @@
-using ClassicSamplesBrowser.Views;
+using Jnana.Views;
using Microsoft.UI.Xaml.Controls;
-using System;
using System.Collections.ObjectModel;
-//using System.Reflection.Metadata;
-//using static ICSharpCode.Decompiler.SingleFileBundle;
+using System;
namespace Jnana.Services;
@@ -16,7 +14,7 @@ public static void Initialize(TabView tabView)
{
_tabView = tabView;
}
- public static void AddPageTab(string header, Type pageType, object? parameter = null, bool selectTab = true)
+ public static void AddPageTab(string header, Type pageType, object? parameter = null, bool selectTab = true)
where T : Control
{
var tab = new TabViewItem
diff --git a/Vanara-Jnana/Vanara/Controls/FeatureTile.xaml b/Vanara-Jnana/Vanara/Controls/FeatureTile.xaml
index 4a7fcccd..bc6e5d5e 100644
--- a/Vanara-Jnana/Vanara/Controls/FeatureTile.xaml
+++ b/Vanara-Jnana/Vanara/Controls/FeatureTile.xaml
@@ -1,5 +1,5 @@
DebugSettings.;
- }
-
// Dependency Properties
public static readonly DependencyProperty TitleProperty =
DependencyProperty.Register(nameof(Title), typeof(string), typeof(FeatureTile),
@@ -38,7 +29,13 @@ public FeatureTile()
((FeatureTile)d).IconElement.Glyph = (string)e.NewValue;
}));
- public event EventHandler Click;
+ public static readonly DependencyProperty CommandProperty =
+ DependencyProperty.Register(nameof(Command), typeof(StandardUICommand), typeof(FeatureTile),
+ new PropertyMetadata(null, (d, e) =>
+ {
+ ((FeatureTile)d).Command = (StandardUICommand)e.NewValue;
+ }));
+
public string Title
{
@@ -58,6 +55,22 @@ public string Icon
set => SetValue(IconProperty, value);
}
+ public event EventHandler Click;
+
+ public StandardUICommand Command
+ {
+ get => (StandardUICommand)GetValue(CommandProperty);
+ set => SetValue(CommandProperty, value);
+ }
+
+ public FeatureTile()
+ {
+ InitializeComponent();
+ SetupInteractions();
+
+ this.Click += (_, __) => Debug.WriteLine($"FeatureTile clicked: Title='{Title}', Subtitle='{Subtitle}'");
+ }
+
private void SetupInteractions()
{
Root.PointerEntered += (_, __) =>
diff --git a/Vanara-Jnana/Vanara/Controls/FloatingStatusBar.xaml b/Vanara-Jnana/Vanara/Controls/FloatingStatusBar.xaml
index 879389bc..a2c71a82 100644
--- a/Vanara-Jnana/Vanara/Controls/FloatingStatusBar.xaml
+++ b/Vanara-Jnana/Vanara/Controls/FloatingStatusBar.xaml
@@ -1,30 +1,33 @@
56
-
-
+
-
-
+
+
+
+
+
diff --git a/Vanara-Jnana/Vanara/Controls/FloatingStatusBar.xaml.cs b/Vanara-Jnana/Vanara/Controls/FloatingStatusBar.xaml.cs
index 14778d63..996241dc 100644
--- a/Vanara-Jnana/Vanara/Controls/FloatingStatusBar.xaml.cs
+++ b/Vanara-Jnana/Vanara/Controls/FloatingStatusBar.xaml.cs
@@ -1,10 +1,11 @@
-using Microsoft.UI.Xaml.Controls;
+using CommunityToolkit.Mvvm.ComponentModel;
using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
using System.ComponentModel;
using System.Runtime.CompilerServices;
-using CommunityToolkit.Mvvm.ComponentModel;
+using WinRT.Interop;
-namespace ClassicSamplesBrowser.Vanara.Controls;
+namespace Jnana.Vanara.Controls;
public sealed partial class FloatingStatusBar : UserControl,
INotifyPropertyChanged
@@ -22,12 +23,22 @@ public FloatingStatusBar()
_hideTimer.Tick += (s, e) => { if (_autoHide) Hide(); };
Show("READY.");
+ ResizeGrip.PointerPressed += ResizeGrip_PointerPressed;
+
/* TODO: Sizer Glyphs:
Klassischer Resize‑Grip E7BF „GripperResize“ – diagonale Linien, wirkt wie der alte Win32‑Grip
Alternative minimal E7C0 „GripperBarHorizontal“ – drei Punkte, subtiler Look
Symbolisch E7C1 „GripperBarVertical“ – vertikale Punkte, wenn du rechts unten eine Spalte andeutest
*/
}
+
+ private void ResizeGrip_PointerPressed(object sender, Microsoft.UI.Xaml.Input.PointerRoutedEventArgs e)
+ {
+ //var hwnd = WindowNative.GetWindowHandle(this);
+
+ // TODO: NativeMethods.SendMessage(hwnd, NativeMethods.WM_NCLBUTTONDOWN, (IntPtr)NativeMethods.HTBOTTOMRIGHT, IntPtr.Zero);
+ }
+
public void Show(string message, string icon = "\uE946")
{
MessageElement.Text = message;
diff --git a/Vanara-Jnana/Vanara/Controls/Shell32AppBar.xaml b/Vanara-Jnana/Vanara/Controls/Shell32AppBar.xaml
index fa5c66c4..2aa665c9 100644
--- a/Vanara-Jnana/Vanara/Controls/Shell32AppBar.xaml
+++ b/Vanara-Jnana/Vanara/Controls/Shell32AppBar.xaml
@@ -1,9 +1,9 @@
diff --git a/Vanara-Jnana/Vanara/Controls/Shell32AppBar.xaml.cs b/Vanara-Jnana/Vanara/Controls/Shell32AppBar.xaml.cs
index 5b2f85d0..dd2873c2 100644
--- a/Vanara-Jnana/Vanara/Controls/Shell32AppBar.xaml.cs
+++ b/Vanara-Jnana/Vanara/Controls/Shell32AppBar.xaml.cs
@@ -3,7 +3,7 @@
// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.
-namespace ClassicSamplesBrowser.Vanara.Controls;
+namespace Jnana.Vanara.Controls;
public sealed partial class Shell32AppBar : UserControl
{
diff --git a/Vanara-Jnana/Vanara/Controls/SidebarControl.xaml b/Vanara-Jnana/Vanara/Controls/SidebarControl.xaml
index 13111e4c..da954380 100644
--- a/Vanara-Jnana/Vanara/Controls/SidebarControl.xaml
+++ b/Vanara-Jnana/Vanara/Controls/SidebarControl.xaml
@@ -1,8 +1,8 @@
LoadVanaraAssemblyTreeAsync()
- {
- // Get Vanara packages from NuGet
-// var packages = await NuGetUtils.GetVanaraPackagesAsync();
-//
-// // Select the latest version (simple for now)
-// var latest = packages.OrderByDescending(p => p.Version).FirstOrDefault();
-// if (latest == null)
-// return null;
-//
-// // Download package and extract DLLs
-// var dllPaths = await NuGetUtils.DownloadAndExtractAssembliesAsync(latest);
-//
-// // Create reflection tree
-// var root = AssemblyElements.CreateFromAssemblies(dllPaths);
-//
-// return root;
- return null;
- }
-}
diff --git a/Vanara-Jnana/Vanara/Services/NavigationService.cs b/Vanara-Jnana/Vanara/Services/NavigationService.cs
deleted file mode 100644
index 8aa8ec3b..00000000
--- a/Vanara-Jnana/Vanara/Services/NavigationService.cs
+++ /dev/null
@@ -1,94 +0,0 @@
-using Microsoft.UI.Xaml.Controls;
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using ClassicSamplesBrowser.Views;
-
-namespace ClassicSamplesBrowser.Vanara.Services;
-
-
-public static class NavigationService
-{
- // The Frame control used for navigation
- private static Frame _frame;
-
- public static void Initialize(Frame frame)
- {
- _frame = frame;
- }
-
- public static List NavigationHistory { get; } = [];
-
- // TODO: Events: Navigated, Navigating, NavigationFailed, NavigationStopped
-
- public static bool CanGoBack => _frame.CanGoBack;
- public static bool CanGoForward => _frame.CanGoForward;
-
-
- public static void NavigateToStart()
- => Navigate(typeof(StartPage));
-
- public static void NavigateToSamples()
- => Navigate(typeof(SamplesPage));
-
- public static void Navigate(Type pageType, object parameter = null)
- {
- try
- {
- _frame.Navigate(pageType, parameter);
- }
- catch (Exception ex)
- {
- Debug.Fail(ex.ToString());
- throw;
- }
- }
-
- public static void GoBack()
- {
- if(CanGoBack)
- {
- _frame.GoBack();
- }
- }
-
- public static void GoForward()
- {
- if(CanGoForward)
- {
- _frame.GoForward();
- }
- }
-
- //// object = null; => Home!
- //public bool Navigate(object navigationTarget, object? parameter = null, bool writeHistory = true)
- //{
- // try
- // {
- // if (navigationTarget != null)
- // {
- // return parameter != null ?
- // Frame.Navigate(navigationTarget.GetType(), parameter)
- // : Frame.Navigate(navigationTarget.GetType());
- // }
-
- // // TODO: search the web
- // }
- // catch (Exception ex)
- // {
- // // Handle navigation exceptions as needed.
- // Debug.WriteLine($"Navigation error: {ex.Message}");
- // return false;
- // }
-
- // if (writeHistory)
- // {
- // // Navigate to the target page and add it to the navigation history
- // }
-
- // return true;
- //}
-}
diff --git a/Vanara-Jnana/ViewModels/GitHubAreaViewModel.cs b/Vanara-Jnana/ViewModels/GitHubAreaViewModel.cs
index a95c537d..213e6e5a 100644
--- a/Vanara-Jnana/ViewModels/GitHubAreaViewModel.cs
+++ b/Vanara-Jnana/ViewModels/GitHubAreaViewModel.cs
@@ -1,11 +1,18 @@
-using ClassicSamplesBrowser.Vanara.Reflection;
-using CommunityToolkit.Mvvm.ComponentModel;
+using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Jnana.Vanara.NuGet;
using System.Collections.ObjectModel;
+using System.Security.Policy;
namespace Jnana.ViewModels;
public partial class GitHubAreaViewModel : ObservableObject
{
+ private readonly Url gitHubRepoUrl = new("https://github.com/vanara/Vanara");
+ private readonly Url gitHubIssuesUrl = new("https://github.com/vanara/Vanara/issues");
+ private readonly Url gitHubPullRequestsUrl = new("https://github.com/vanara/Vanara/pulls");
+
+ public Url GitHubRepoUrl => gitHubRepoUrl;
+ public Url GitHubIssuesUrl => gitHubIssuesUrl;
+ public Url GitHubPullRequestsUrl => gitHubPullRequestsUrl;
}
diff --git a/Vanara-Jnana/ViewModels/NuGetPackageDetailViewModel.cs b/Vanara-Jnana/ViewModels/NuGetPackageDetailViewModel.cs
new file mode 100644
index 00000000..be5d0484
--- /dev/null
+++ b/Vanara-Jnana/ViewModels/NuGetPackageDetailViewModel.cs
@@ -0,0 +1,68 @@
+using CommunityToolkit.Mvvm.ComponentModel;
+using Jnana.Helpers;
+using Jnana.Services;
+using Microsoft.UI.Xaml.Media.Imaging;
+using NuGet.Versioning;
+
+namespace Jnana.ViewModels;
+
+public sealed partial class NuGetPackageDetailViewModel : ObservableObject
+{
+ private readonly INuGetCatalogService _catalog;
+ private PackageContent? _content;
+ public string? Id => _content?.Id;
+ public string? Version => _content?.Version?.ToNormalizedString();
+ public string? Readme => _content?.Readme;
+
+ private BitmapImage? _icon;
+ public BitmapImage? Icon
+ {
+ get
+ {
+ if (_icon == null && _content?.IconBytes != null)
+ _icon = ImageExtensions.ToBitmapImage(_content.IconBytes);
+ return _icon;
+ }
+ }
+ public NuGetPackageDetailViewModel(INuGetCatalogService catalog)
+ {
+ _catalog = catalog;
+
+ // TODO: Consider adding a placeholder icon here while the real one is loading, or if it fails to load.
+ // TODO: Bind Details Pane against Package Details View Model, and show
+ }
+
+ public async Task LoadAsync(string id, NuGetVersion version, CancellationToken token)
+ {
+ _content = await _catalog.DownloadPackageAsync(id, version, token);
+ OnPropertyChanged(nameof(Id));
+ OnPropertyChanged(nameof(Version));
+ OnPropertyChanged(nameof(Readme));
+ OnPropertyChanged(nameof(Icon));
+ }
+
+ public void Clear()
+ {
+ _content = null;
+ _icon = null;
+ OnPropertyChanged(nameof(Id));
+ OnPropertyChanged(nameof(Version));
+ OnPropertyChanged(nameof(Readme));
+ OnPropertyChanged(nameof(Icon));
+ }
+
+ /*
+ // Handle the selection of the package version info
+ //await PackageDetailViewModel.LoadAsync(SelectedPackage.Id, NuGet.Versioning.NuGetVersion.Parse(SelectedPackage.Version), cancelToken).ContinueWith(t =>
+ //{
+ // if (t.IsFaulted)
+ // {
+ // Debug.Print($"Failed to load package details: {t.Exception}");
+ // //logger?.LogError(t.Exception, "Failed to load package details");
+ // }
+ //}, cancelToken);
+ //
+ //await PackageDetailViewModel.LoadAsync(SelectedPackage.Id, NuGet.Versioning.NuGetVersion.Parse(SelectedPackage.Version), CancellationToken.None);
+
+ */
+}
diff --git a/Vanara-Jnana/ViewModels/NuGetsAreaViewModel.cs b/Vanara-Jnana/ViewModels/NuGetsAreaViewModel.cs
index 0b278d9b..15b43781 100644
--- a/Vanara-Jnana/ViewModels/NuGetsAreaViewModel.cs
+++ b/Vanara-Jnana/ViewModels/NuGetsAreaViewModel.cs
@@ -1,138 +1,68 @@
-using ClassicSamplesBrowser.Vanara.Reflection;
-using CommunityToolkit.Mvvm.ComponentModel;
+using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
-using Jnana.Vanara.NuGet;
+using Jnana.Services;
+using NuGet.Common;
+using NuGet.Versioning;
using System.Collections.ObjectModel;
using System.Windows.Input;
+using Windows.ApplicationModel.Background;
namespace Jnana.ViewModels;
public partial class NuGetsAreaViewModel : ObservableObject
{
- // TODO: Use `NuGetPackageInfo` here:
- public ObservableCollection Packages { get; } =
- new ObservableCollection();
+ private readonly NuGetCatalogService nuGetCatalogService;
+ private readonly NuGetCatalogMemoryCache nuGetCatalogMemoryCache;
+ private readonly NuGetCatalogDiskCache nuGetCatalogDiskCache;
- public ICommand RefreshCommand { get; }
+ /// Get the current INuGetCatalogService that is in use.
+ public INuGetCatalogService NuGetCatalogService => nuGetCatalogDiskCache;
- public NuGetsAreaViewModel()
+ public ObservableCollection Packages { get; } = new();
+
+ public NuGetPackageDetailViewModel PackageDetailViewModel { get; }
+
+ public ICommand SelectVersionCommand { get; }
+
+ public NuGetsAreaViewModel(ILogger? logger = null)
{
- RefreshCommand = new RelayCommand(LoadPackages);
+ nuGetCatalogService = new NuGetCatalogService("https://api.nuget.org/v3/index.json", logger);
+ nuGetCatalogMemoryCache = new NuGetCatalogMemoryCache(nuGetCatalogService);
+
+ var cachePath = Path.Combine(
+ Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Jnana", "nuget-cache.json");
+
+ nuGetCatalogDiskCache = new NuGetCatalogDiskCache(nuGetCatalogMemoryCache, cachePath);
+ PackageDetailViewModel = new NuGetPackageDetailViewModel(nuGetCatalogDiskCache);
+
+ SelectVersionCommand = new RelayCommand(OnVersionSelected);
}
- private void LoadPackages()
+ public async Task SynchronizePackageCacheAsync()
{
- // TODO: API call
+ // TODO: Instead of clearing the entire cache, consider implementing a more efficient synchronization strategy that only updates changed packages.
+ Packages.Clear();
+
+ await foreach (var pkg in nuGetCatalogDiskCache.SearchPackagesAsync("Vanara.", CancellationToken.None))
+ {
+ var latest = await nuGetCatalogDiskCache.GetLatestStableVersionAsync(pkg.Id, CancellationToken.None);
+ if (latest != null)
+ Packages.Add(latest);
+ }
}
- // private readonly AssemblyLoaderService _loader;
- //
- // public NuGetViewModel(AssemblyLoaderService loader)
- // {
- // _loader = loader;
- //
- // Packages = new ObservableCollection();
- // Versions = new ObservableCollection();
- // }
- //
- // // -----------------------------
- // // Collections
- // // -----------------------------
- // public ObservableCollection Packages { get; }
- // public ObservableCollection Versions { get; }
- //
- // // -----------------------------
- // // Selected Items
- // // -----------------------------
- // [ObservableProperty]
- // private NuGetPackageInfo? selectedPackage;
- //
- // partial void OnSelectedPackageChanged(NuGetPackageInfo? value)
- // {
- // if (value != null)
- // LoadVersionsCommand.Execute(value);
- // }
- //
- // [ObservableProperty]
- // private string? selectedVersion;
- //
- // partial void OnSelectedVersionChanged(string? value)
- // {
- // if (value != null)
- // LoadAssemblyTreeCommand.Execute(value);
- // }
- //
- // // -----------------------------
- // // Reflection Root
- // // -----------------------------
- // [ObservableProperty]
- // private IElementInfo? rootElement;
- //
- // // -----------------------------
- // // Loading Flags
- // // -----------------------------
- // [ObservableProperty] private bool isLoadingPackages;
- // [ObservableProperty] private bool isLoadingVersions;
- // [ObservableProperty] private bool isLoadingAssemblies;
- //
- // // -----------------------------
- // // Commands
- // // -----------------------------
- // [RelayCommand]
- // private async Task LoadPackagesAsync()
- // {
- // try
- // {
- // IsLoadingPackages = true;
- // Packages.Clear();
- //
- // var pkgs = await _nuget.GetVanaraPackagesAsync();
- //
- // foreach (var pkg in pkgs)
- // Packages.Add(pkg);
- // }
- // finally
- // {
- // IsLoadingPackages = false;
- // }
- // }
- //
- // [RelayCommand]
- // private async Task LoadVersionsAsync(NuGetPackageInfo package)
- // {
- // try
- // {
- // IsLoadingVersions = true;
- // Versions.Clear();
- //
- // var versions = await _nuget.GetPackageVersionsAsync(package.Id);
- //
- // foreach (var v in versions)
- // Versions.Add(v);
- // }
- // finally
- // {
- // IsLoadingVersions = false;
- // }
- // }
- //
- // [RelayCommand]
- // private async Task LoadAssemblyTreeAsync(string version)
- // {
- // try
- // {
- // IsLoadingAssemblies = true;
- //
- // var assemblies = await _nuget.DownloadAndExtractAssembliesAsync(
- // SelectedPackage!.Id,
- // version
- // );
- //
- // RootElement = await _loader.LoadFromAssembliesAsync(assemblies);
- // }
- // finally
- // {
- // IsLoadingAssemblies = false;
- // }
- // }
+ private async void OnVersionSelected(PackageVersionInfo? version)
+ {
+ if (version != null)
+ {
+ // TODO: Update package Detail view with the selected version
+ await PackageDetailViewModel.LoadAsync(version.Id, NuGetVersion.Parse(version.Version), CancellationToken.None);
+ }
+ else
+ {
+ // Make sure all values are cleared if no version is selected
+ PackageDetailViewModel.Clear();
+ }
+ // TODO: Update Details pane to show the selected version's details
+ }
}
diff --git a/Vanara-Jnana/ViewModels/UtilitiesAreaViewModel.cs b/Vanara-Jnana/ViewModels/UtilitiesAreaViewModel.cs
new file mode 100644
index 00000000..5854cab0
--- /dev/null
+++ b/Vanara-Jnana/ViewModels/UtilitiesAreaViewModel.cs
@@ -0,0 +1,11 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Jnana.ViewModels;
+
+internal class UtilitiesAreaViewModel
+{
+}
diff --git a/Vanara-Jnana/ViewModels/VoidPageViewModel.cs b/Vanara-Jnana/ViewModels/VoidPageViewModel.cs
index 83af207e..87321b3e 100644
--- a/Vanara-Jnana/ViewModels/VoidPageViewModel.cs
+++ b/Vanara-Jnana/ViewModels/VoidPageViewModel.cs
@@ -12,63 +12,17 @@ namespace Jnana.ViewModels;
public partial class VoidPageViewModel : ObservableObject
{
- public NuGetsAreaViewModel NuGetArea { get; }
- public GitHubAreaViewModel GitHubArea { get; }
- public SamplesAreaViewModel SamplesArea { get; }
-
- public List NugetItems => ["NuGet", "GitHub", "Samples"];
-
- private object _currentArea;
- public object CurrentArea
- {
- get => _currentArea;
- set => SetProperty(ref _currentArea, value);
- }
-
- public ICommand NavigateCommand { get; }
+ public NuGetsAreaViewModel NuGetsViewModel { get; }
+ public GitHubAreaViewModel GitHubViewModel { get; }
+ public SamplesAreaViewModel SamplesViewModel { get; }
public VoidPageViewModel(
NuGetsAreaViewModel nuget,
GitHubAreaViewModel github,
SamplesAreaViewModel samples)
{
- NuGetArea = nuget;
- GitHubArea = github;
- SamplesArea = samples;
-
- CurrentArea = NuGetArea;
-
- NavigateCommand = new RelayCommand(OnNavigate);
- }
-
- private void OnNavigate(string target)
- {
- CurrentArea = target switch
- {
- "NuGet" => NuGetArea,
- "GitHub" => GitHubArea,
- "Samples" => SamplesArea,
- _ => CurrentArea
- };
+ NuGetsViewModel = nuget;
+ GitHubViewModel = github;
+ SamplesViewModel = samples;
}
-
- ///
- /// the following properties are just placeholders for the actual content of each area. In a real application, these would likely be more complex types representing the data and functionality of each area.
- ///
-// public List NugetItems { get; set; }
-// public List GitHubItems { get; set; }
-// public List SamplesItems { get; set; }
}
-
-// internal class VoidPageViewModel {
-// public List NugetItems { get; set; }
-// public List GitHubItems { get; set; }
-// public List SamplesItems { get; set; }
-// public VoidPageViewModel()
-// { NugetItems = new List();
-// GitHubItems = new List();
-// SamplesItems = new List();
-//
-// NugetItems.AddRange(new String[] { "Vanara.Core", "Vanara.PInvoke", "Vanara.Windows", "etc." });
-// GitHubItems.AddRange(new String[] { "Home", "Releases", "Issues", "Pull Requests" });
-// SamplesItems.AddRange(new String[] { "Item 1", "Item 2", "Item 3", "etc." }); } }
diff --git a/Vanara-Jnana/Views/GitHubPage.xaml b/Vanara-Jnana/Views/GitHubPage.xaml
index 3da8b0e2..621b5282 100644
--- a/Vanara-Jnana/Views/GitHubPage.xaml
+++ b/Vanara-Jnana/Views/GitHubPage.xaml
@@ -1,8 +1,8 @@
+
diff --git a/Vanara-Jnana/Views/GitHubPage.xaml.cs b/Vanara-Jnana/Views/GitHubPage.xaml.cs
index 1fcf3d28..9dc9d752 100644
--- a/Vanara-Jnana/Views/GitHubPage.xaml.cs
+++ b/Vanara-Jnana/Views/GitHubPage.xaml.cs
@@ -1,39 +1,11 @@
using Microsoft.UI.Xaml.Controls;
-namespace ClassicSamplesBrowser.Views;
+namespace Jnana.Views;
public sealed partial class GitHubPage : Page
{
public GitHubPage()
{
InitializeComponent();
-
- //ContentFrame.Navigate(typeof(HomePage));
}
-
-// private void NavView_SelectionChanged(NavigationView sender, NavigationViewSelectionChangedEventArgs args)
-// {
-// if (args.SelectedItem is NavigationViewItem item)
-// {
-// var tag = item.Tag?.ToString();
-//
-// switch (tag)
-// {
-// case "HomePage":
-// ContentFrame.Navigate(typeof(HomePage));
-// //HeaderTitle.Text = "Home";
-// break;
-//
-// case "SamplesPage":
-// ContentFrame.Navigate(typeof(SamplesPage));
-// //HeaderTitle.Text = "Samples";
-// break;
-//
-// case "AboutPage":
-// ContentFrame.Navigate(typeof(AboutPage));
-// //HeaderTitle.Text = "About";
-// break;
-// }
-// }
-// }
}
\ No newline at end of file
diff --git a/Vanara-Jnana/Views/NuGetsPage.xaml b/Vanara-Jnana/Views/NuGetsPage.xaml
index 6647002b..c5fe8889 100644
--- a/Vanara-Jnana/Views/NuGetsPage.xaml
+++ b/Vanara-Jnana/Views/NuGetsPage.xaml
@@ -1,20 +1,62 @@
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:tkcontrols="using:CommunityToolkit.WinUI.Controls">
-
+
-
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Vanara-Jnana/Views/NuGetsPage.xaml.cs b/Vanara-Jnana/Views/NuGetsPage.xaml.cs
index 971cb1cb..1a405962 100644
--- a/Vanara-Jnana/Views/NuGetsPage.xaml.cs
+++ b/Vanara-Jnana/Views/NuGetsPage.xaml.cs
@@ -1,17 +1,51 @@
+using CommunityToolkit.Mvvm.Input;
+using Jnana.Services;
+using Jnana.ViewModels;
using Microsoft.UI.Xaml.Controls;
+using NuGet.Common;
+using NuGet.Versioning;
+using System.Diagnostics;
+using System.Windows.Input;
-// To learn more about WinUI, the WinUI project structure,
-// and more about our project templates, see: http://aka.ms/winui-project-info.
+namespace Jnana.Views;
-namespace ClassicSamplesBrowser.Views;
-
-///
-/// An empty page that can be used on its own or navigated to within a Frame.
-///
public sealed partial class NuGetsPage : Page
{
+ private readonly ILogger? logger;
+ public NuGetsAreaViewModel ViewModel { get; }
+
+ private CancellationToken cancelToken = CancellationToken.None;
+ public PackageVersionInfo? SelectedPackage { get; private set; } = null;
+
public NuGetsPage()
{
InitializeComponent();
+
+ logger = new NullLogger();
+ ViewModel = new NuGetsAreaViewModel(logger);
+
+
+ ViewModel.SynchronizePackageCacheAsync().ContinueWith(t =>
+ {
+ if (t.IsFaulted)
+ {
+ Debug.Print($"Failed to load NuGet packages: {t.Exception}");
+ //logger?.LogError(t.Exception, "Failed to load NuGet packages");
+ }
+ }, cancelToken);
+ }
+
+ private void PackageTreeView_SelectionChanged(TreeView sender, TreeViewSelectionChangedEventArgs args)
+ {
+ if (sender.Equals(PackageTreeView))
+ {
+ SelectedPackage = args.AddedItems.FirstOrDefault() as PackageVersionInfo;
+
+ if (SelectedPackage != null)
+ {
+ Debug.Print($"Selected package: {SelectedPackage.Id} {SelectedPackage.Version}");
+ ViewModel.SelectVersionCommand.Execute(SelectedPackage);
+ }
+ }
}
-}
\ No newline at end of file
+}
diff --git a/Vanara-Jnana/Views/SamplesPage.xaml b/Vanara-Jnana/Views/SamplesPage.xaml
index 53f3598c..a6b5289e 100644
--- a/Vanara-Jnana/Views/SamplesPage.xaml
+++ b/Vanara-Jnana/Views/SamplesPage.xaml
@@ -1,8 +1,8 @@
+ xmlns:controls="using:Jnana.Vanara.Controls">
diff --git a/Vanara-Jnana/Views/SamplesPage.xaml.cs b/Vanara-Jnana/Views/SamplesPage.xaml.cs
index 3d80cb2b..9cf905d1 100644
--- a/Vanara-Jnana/Views/SamplesPage.xaml.cs
+++ b/Vanara-Jnana/Views/SamplesPage.xaml.cs
@@ -3,7 +3,7 @@
// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.
-namespace ClassicSamplesBrowser.Views;
+namespace Jnana.Views;
///
/// An empty page that can be used on its own or navigated to within a Frame.
diff --git a/Vanara-Jnana/Views/SettingsPage.xaml b/Vanara-Jnana/Views/SettingsPage.xaml
index 9cec3438..5ae820eb 100644
--- a/Vanara-Jnana/Views/SettingsPage.xaml
+++ b/Vanara-Jnana/Views/SettingsPage.xaml
@@ -1,19 +1,28 @@
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+ Light
+ Dark
+ High Contrast
+
+
+
+
+
+
+
diff --git a/Vanara-Jnana/Views/SettingsPage.xaml.cs b/Vanara-Jnana/Views/SettingsPage.xaml.cs
index 52ced7cc..e24ab763 100644
--- a/Vanara-Jnana/Views/SettingsPage.xaml.cs
+++ b/Vanara-Jnana/Views/SettingsPage.xaml.cs
@@ -3,7 +3,7 @@
// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.
-namespace ClassicSamplesBrowser.Views;
+namespace Jnana.Views;
///
/// An empty page that can be used on its own or navigated to within a Frame.
diff --git a/Vanara-Jnana/Views/ShellPage.xaml b/Vanara-Jnana/Views/ShellPage.xaml
index d37d9800..429c6fc1 100644
--- a/Vanara-Jnana/Views/ShellPage.xaml
+++ b/Vanara-Jnana/Views/ShellPage.xaml
@@ -1,9 +1,9 @@
-
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
@@ -90,11 +92,14 @@
-
+
-
+
diff --git a/Vanara-Jnana/Views/ShellPage.xaml.cs b/Vanara-Jnana/Views/ShellPage.xaml.cs
index 5cdc08b8..b5556fb6 100644
--- a/Vanara-Jnana/Views/ShellPage.xaml.cs
+++ b/Vanara-Jnana/Views/ShellPage.xaml.cs
@@ -1,63 +1,114 @@
-using ClassicSamplesBrowser.Services;
using CommunityToolkit.Mvvm.Input;
+using Jnana.Models;
+using Jnana.Services;
using Jnana.ViewModels;
-using Microsoft.UI.Xaml.Controls.Primitives;
using Microsoft.UI.Xaml.Controls;
-using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Input;
-using Microsoft.UI.Xaml.Media;
-using Microsoft.UI.Xaml.Navigation;
-using Microsoft.UI.Xaml;
-using System.Collections.Generic;
+using System.Collections.ObjectModel;
using System.Diagnostics;
-using System.IO;
-using System.Linq;
-using System.Runtime.InteropServices.WindowsRuntime;
using System.Windows.Input;
-using System;
-using Windows.Foundation.Collections;
-using Windows.Foundation;
-namespace ClassicSamplesBrowser.Views;
+namespace Jnana.Views;
public sealed partial class ShellPage : Page
{
- static readonly CancellationToken CancellationToken = CancellationToken.None;
- private NuGetsAreaViewModel NuGetVM { get; }
+ private NuGetsAreaViewModel NuGetsVM { get; }
private GitHubAreaViewModel GitHubVM { get; }
private SamplesAreaViewModel SamplesVM { get; }
private NavigationService _navigationService { get; }
+ // TODO: Consider making this a user setting that can be persisted across sessions, or determining it based on the last visited area
+ // TODO: @dahall this is where you currently set the default navigation target...
+ private readonly INavigationService.Area defaultNavigationTarget = INavigationService.Area.Void;
+ private ObservableCollection Tabs { get; }
+
+ public StandardUICommand NavigateCommand => new(StandardUICommandKind.Open);
+ public ICommand OpenNewTabCommand { get; }
+
+ public TabViewItem SelectedTab { get; set; }
+
public ShellPage()
{
InitializeComponent();
- NuGetVM = new NuGetsAreaViewModel();
+ NuGetsVM = new NuGetsAreaViewModel();
GitHubVM = new GitHubAreaViewModel();
SamplesVM = new SamplesAreaViewModel();
-
_navigationService = new NavigationService(MainFrame); // TODO: Use dependency injection to provide the NavigationService instance, and consider making it a singleton if it doesn't need to maintain any state
- // OnLoading: Navigate to the default area (Void) to ensure the main content area is populated with a page, and to establish a consistent starting point for navigation
- _navigationService.NavigateTo(INavigationService.Area.Void);
- //_navigationService.NavigateTo(INavigationService.Area.Settings);
+ _ = NuGetsVM.SynchronizePackageCacheAsync();
+
+ // OnLoading: Navigate to the default area (Void) to ensure the main content area
+ // is populated with a page, and to establish a consistent starting point for navigation
+ // TODO: WARN: This is the initial navigation target, but it should be determined based on user settings or the last visited area to provide a more personalized experience
+ _navigationService.NavigateTo(defaultNavigationTarget);
+
+ OpenNewTabCommand = new RelayCommand(OpenNewTab);
+ NavigateCommand.ExecuteRequested += NavigateCommand_ExecuteRequested;
+ }
+
+ private void AddNewTab(string header, Page page, IconSource? iconSource = null)
+ {
+ Debug.Print($"Adding new tab with header: {header}, page: {page.GetType().Name}, icon: {(iconSource != null ? iconSource.GetType().Name : "null")}");
+
+ try
+ {
+ var tabViewIconSource = iconSource ?? new SymbolIconSource { Symbol = Symbol.Document };
+ var newTab = new TabViewItem
+ {
+ Content = new Frame(),
+ Header = header,
+ IconSource = tabViewIconSource,
+ };
+
+ // Navigate the new tab's frame to the specified page
+ ((Frame)newTab.Content).Navigate(page.GetType());
+
+ // Add new tab and select it
+ MainTabView.TabItems.Add(newTab);
+ MainTabView.SelectedItem = newTab;
+ }
+ catch (Exception ex)
+ {
+ Debug.Fail($"Failed to to create new tab {header}: {ex}");
+ }
+ }
+
+ private void OpenNewTab(string? header)
+ {
+ var tab = new TabViewItem
+ {
+ Header = header ?? "New Tab",
+ Content = new Frame()
+ };
+
+ ((Frame)tab.Content).Navigate(typeof(VoidPage));
+
+ Tabs.Add(tab);
+ SelectedTab = tab;
}
- public ICommand NavigateCommand => new RelayCommand(areaName =>
+ private void NavigateCommand_ExecuteRequested(XamlUICommand sender, ExecuteRequestedEventArgs args)
{
- if (Enum.TryParse(areaName, out INavigationService.Area area))
- _navigationService.NavigateTo(area);
- });
+ Debug.Print("TODO: NavigateCommand_ExecuteRequested()");
+ }
+
+ private void MainTabView_AddTabButtonClick(TabView sender, object args)
+ {
+ AddNewTab("NuGets", new NuGetsPage());
+ }
private void NavBreadcrumb_ItemClicked(object sender, BreadcrumbBarItemClickedEventArgs args)
{
var clicked = args.Item.ToString();
Debug.WriteLine($"Breadcrumb item clicked: {clicked} (TODO: Navigate to the clicked item)");
}
+
private void SearchBox_QuerySubmitted(AutoSuggestBox sender, AutoSuggestBoxQuerySubmittedEventArgs args)
{
var query = args.QueryText;
- Debug.WriteLine($"Search query submitted: {query} (TODO: Handle search query submission)");
query = query.Trim();
+ Debug.WriteLine($"Search query submitted: {query} (TODO: Handle search query submission)");
}
+
private void SearchBox_TextChanged(AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args)
{
Debug.WriteLine($"Search box text changed: {sender.Text} {args.ToString} (TODO: Handle text change)");
diff --git a/Vanara-Jnana/Views/StartPage.xaml b/Vanara-Jnana/Views/StartPage.xaml
index 14ab6daa..75b1392b 100644
--- a/Vanara-Jnana/Views/StartPage.xaml
+++ b/Vanara-Jnana/Views/StartPage.xaml
@@ -1,8 +1,8 @@
/// StartPage is the main page that is shown when the app is launched
diff --git a/Vanara-Jnana/Views/UtilitiesPage.xaml b/Vanara-Jnana/Views/UtilitiesPage.xaml
index f6c07db3..af8144c5 100644
--- a/Vanara-Jnana/Views/UtilitiesPage.xaml
+++ b/Vanara-Jnana/Views/UtilitiesPage.xaml
@@ -1,20 +1,51 @@
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Vanara-Jnana/Views/UtilitiesPage.xaml.cs b/Vanara-Jnana/Views/UtilitiesPage.xaml.cs
index 8d7e0786..2d07dc1b 100644
--- a/Vanara-Jnana/Views/UtilitiesPage.xaml.cs
+++ b/Vanara-Jnana/Views/UtilitiesPage.xaml.cs
@@ -1,31 +1,20 @@
-using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
-using Microsoft.UI.Xaml.Controls.Primitives;
-using Microsoft.UI.Xaml.Data;
-using Microsoft.UI.Xaml.Input;
-using Microsoft.UI.Xaml.Media;
-using Microsoft.UI.Xaml.Navigation;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Runtime.InteropServices.WindowsRuntime;
-using Windows.Foundation;
-using Windows.Foundation.Collections;
-// To learn more about WinUI, the WinUI project structure,
-// and more about our project templates, see: http://aka.ms/winui-project-info.
+namespace Jnana.Views;
-namespace ClassicSamplesBrowser.Views
+public sealed partial class UtilitiesPage : Page
{
- ///
- /// An empty page that can be used on its own or navigated to within a Frame.
- ///
- public sealed partial class UtilitiesPage : Page
+ public UtilitiesPage()
{
- public UtilitiesPage()
- {
- InitializeComponent();
- }
+ InitializeComponent();
+ //Loaded += OnLoaded;
}
+
+ //private void OnLoaded(object sender, RoutedEventArgs e)
+ //{
+ // if (!ToolManager.HasOpenTools)
+ // {
+ // ToolManager.Open();
+ // }
+ //}
}
diff --git a/Vanara-Jnana/Views/VoidPage.xaml b/Vanara-Jnana/Views/VoidPage.xaml
index d4504847..291a5c24 100644
--- a/Vanara-Jnana/Views/VoidPage.xaml
+++ b/Vanara-Jnana/Views/VoidPage.xaml
@@ -4,9 +4,12 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:Jnana.Views"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ xmlns:toolkit="using:CommunityToolkit.WinUI.Controls"
xmlns:viewmodels="using:Jnana.ViewModels"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:controls="using:CommunityToolkit.WinUI.Controls"
+ d:DataContext="{d:DesignInstance Type=viewmodels:VoidPageViewModel}"
mc:Ignorable="d">
@@ -16,79 +19,45 @@
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
-
+
-
-
+
-
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
+
-
+
diff --git a/Vanara-Jnana/Views/VoidPage.xaml.cs b/Vanara-Jnana/Views/VoidPage.xaml.cs
index 685ada6b..c5163a33 100644
--- a/Vanara-Jnana/Views/VoidPage.xaml.cs
+++ b/Vanara-Jnana/Views/VoidPage.xaml.cs
@@ -1,50 +1,21 @@
using Jnana.ViewModels;
-using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
-using Microsoft.UI.Xaml.Controls.Primitives;
-using Microsoft.UI.Xaml.Data;
-using Microsoft.UI.Xaml.Input;
-using Microsoft.UI.Xaml.Media;
-using Microsoft.UI.Xaml.Navigation;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Runtime.InteropServices.WindowsRuntime;
-using Windows.Foundation;
-using Windows.Foundation.Collections;
namespace Jnana.Views;
public sealed partial class VoidPage : Page
{
private VoidPageViewModel ViewModel { get; }
+
public VoidPage()
{
InitializeComponent();
- // TODO: ViewModel = new VoidPageViewModel();
-// GitHubPreview.CoreWebView2Initialized += (_, __) =>
-// {
-// // TODO: Is this call ever reached?
-// var wv = GitHubPreview.CoreWebView2;
-//
-// // Disable context menus, dev tools, zoom, and status bar
-// wv.Settings.AreDefaultContextMenusEnabled = false;
-// wv.Settings.AreDevToolsEnabled = false;
-// wv.Settings.IsZoomControlEnabled = false;
-// wv.Settings.IsStatusBarEnabled = false;
-//
-// // Disable built-in error page to prevent it from showing when loading fails
-// //wv.Settings.IsBuiltInErrorPageEnabled = false;
-//
-// // Inject CSS to hide Scrollbars and prevent scrolling (optional, can be adjusted as needed)
-// //wv.AddScriptToExecuteOnDocumentCreatedAsync(@"
-// //const style = document.createElement('style');
-// //style.innerHTML =
-// // `::-webkit-scrollbar { display: none; }
-// // body { overflow: hidden !important; }
-// //`; document.head.appendChild(style); ");
-// };
+ // TODO: Consider using dependency injection to provide these view models,
+ // especially if they need to maintain state or interact with services
+ ViewModel = new VoidPageViewModel(
+ new NuGetsAreaViewModel(),
+ new GitHubAreaViewModel(),
+ new SamplesAreaViewModel());
}
}