diff --git a/Material.Icons.Maui.Demo/App.xaml b/Material.Icons.Maui.Demo/App.xaml
new file mode 100644
index 0000000..fbd263b
--- /dev/null
+++ b/Material.Icons.Maui.Demo/App.xaml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Material.Icons.Maui.Demo/App.xaml.cs b/Material.Icons.Maui.Demo/App.xaml.cs
new file mode 100644
index 0000000..6066e31
--- /dev/null
+++ b/Material.Icons.Maui.Demo/App.xaml.cs
@@ -0,0 +1,10 @@
+namespace Material.Icons.Maui.Demo;
+
+public partial class App {
+ public App() {
+ InitializeComponent();
+
+ // UserAppTheme = AppTheme.Light;
+ MainPage = new AppShell();
+ }
+}
diff --git a/Material.Icons.Maui.Demo/AppShell.xaml b/Material.Icons.Maui.Demo/AppShell.xaml
new file mode 100644
index 0000000..ad2cd07
--- /dev/null
+++ b/Material.Icons.Maui.Demo/AppShell.xaml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
diff --git a/Material.Icons.Maui.Demo/AppShell.xaml.cs b/Material.Icons.Maui.Demo/AppShell.xaml.cs
new file mode 100644
index 0000000..a56f8bf
--- /dev/null
+++ b/Material.Icons.Maui.Demo/AppShell.xaml.cs
@@ -0,0 +1,9 @@
+namespace Material.Icons.Maui.Demo;
+
+public partial class AppShell {
+ public AppShell() {
+ InitializeComponent();
+
+ Routing.RegisterRoute("Main/Details", typeof(DetailsPage));
+ }
+}
diff --git a/Material.Icons.Maui.Demo/DetailsPage.xaml b/Material.Icons.Maui.Demo/DetailsPage.xaml
new file mode 100644
index 0000000..8c67b87
--- /dev/null
+++ b/Material.Icons.Maui.Demo/DetailsPage.xaml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Material.Icons.Maui.Demo/DetailsPage.xaml.cs b/Material.Icons.Maui.Demo/DetailsPage.xaml.cs
new file mode 100644
index 0000000..f6be2f7
--- /dev/null
+++ b/Material.Icons.Maui.Demo/DetailsPage.xaml.cs
@@ -0,0 +1,8 @@
+namespace Material.Icons.Maui.Demo;
+
+[QueryProperty(nameof(ViewModel), "ViewModel")]
+public partial class DetailsPage {
+ public DetailsPage() {
+ InitializeComponent();
+ }
+}
diff --git a/Material.Icons.Maui.Demo/DetailsViewModel.cs b/Material.Icons.Maui.Demo/DetailsViewModel.cs
new file mode 100644
index 0000000..39693ca
--- /dev/null
+++ b/Material.Icons.Maui.Demo/DetailsViewModel.cs
@@ -0,0 +1,14 @@
+using DynamicData.Binding;
+
+using ReactiveUI;
+using ReactiveUI.SourceGenerators;
+
+namespace Material.Icons.Maui.Demo;
+
+public partial class DetailsViewModel : ReactiveObject {
+ [Reactive]
+ private PackIconKindGroup? _selectedIcon;
+
+ [Reactive]
+ private ObservableCollectionExtended _icons = [];
+}
diff --git a/Material.Icons.Maui.Demo/MainPage.xaml b/Material.Icons.Maui.Demo/MainPage.xaml
new file mode 100644
index 0000000..7bb3284
--- /dev/null
+++ b/Material.Icons.Maui.Demo/MainPage.xaml
@@ -0,0 +1,72 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Material.Icons.Maui.Demo/MainPage.xaml.cs b/Material.Icons.Maui.Demo/MainPage.xaml.cs
new file mode 100644
index 0000000..039da1f
--- /dev/null
+++ b/Material.Icons.Maui.Demo/MainPage.xaml.cs
@@ -0,0 +1,21 @@
+using ReactiveUI;
+
+namespace Material.Icons.Maui.Demo;
+
+public partial class MainPage {
+ public MainPage(MainViewModel viewModel) {
+ Controls.Init();
+
+ BindingContext = viewModel;
+
+ InitializeComponent();
+
+ this.WhenActivated(d => {
+ this.BindCommand(
+ ViewModel,
+ vm => vm.ShowDetails,
+ v => v.ShowDetails,
+ vm => vm.Group);
+ });
+ }
+}
diff --git a/Material.Icons.Maui.Demo/MainViewModel.cs b/Material.Icons.Maui.Demo/MainViewModel.cs
new file mode 100644
index 0000000..e08ab7c
--- /dev/null
+++ b/Material.Icons.Maui.Demo/MainViewModel.cs
@@ -0,0 +1,90 @@
+using System.Reactive;
+using System.Reactive.Linq;
+
+using DynamicData.Binding;
+using DynamicData;
+
+using ReactiveUI;
+using ReactiveUI.SourceGenerators;
+
+namespace Material.Icons.Maui.Demo;
+
+public partial class MainViewModel : ReactiveObject {
+ [Reactive]
+ private SourceList _kindsSource = new();
+
+ [Reactive]
+ private ObservableCollectionExtended _kinds = new();
+
+ [Reactive]
+ private string? _searchText;
+
+ [Reactive]
+ private PackIconKindGroup? _group;
+
+ [ObservableAsProperty]
+ private string? _copyText;
+
+ public MainViewModel() {
+ _kindsSource.AddRange(
+ (from name in Enum.GetNames()
+ let kind = Enum.Parse(name)
+ let value = (int)kind
+ let item = (Name: name, Kind: kind, Value: value)
+ group item by item.Value
+ into g
+ select new PackIconKindGroup(g.Select(x => x.Name)))
+ .OrderBy(x => x.DisplayName));
+
+ Group = _kindsSource.Items.FirstOrDefault();
+
+ var kindsFilter = this.WhenAnyValue(x => x.SearchText)
+ .Select(text => string.IsNullOrEmpty(text)
+ ? CreateUnfilteredFilter()
+ : CreateTextFilter(text))
+ .Throttle(TimeSpan.FromMilliseconds(250));
+
+ _kindsSource
+ .Connect()
+ .Filter(kindsFilter)
+ .Sort(SortExpressionComparer.Ascending(p => p.DisplayName))
+ .ObserveOn(RxApp.MainThreadScheduler)
+ .Bind(_kinds)
+ .Subscribe();
+
+ _copyTextHelper = this.WhenAnyValue(x => x.Group)
+ .Select(value => value is null ? null : $"")
+ .ToProperty(this, x => x.CopyText);
+
+ DetailsViewModel = new DetailsViewModel() {
+ Icons = _kinds,
+ SelectedIcon = Group,
+ };
+
+ DetailsViewModel.WhenAnyValue(x => x.SelectedIcon)
+ .Subscribe(item => Group = item);
+
+ var canShowDetails = this.WhenAnyValue(x => x.Group)
+ .Select(value => value is not null);
+ ShowDetails = ReactiveCommand.CreateFromTask(ShowDetailsAsync, canShowDetails);
+ }
+
+ public DetailsViewModel DetailsViewModel { get; }
+
+ public ReactiveCommand ShowDetails { get; }
+
+ private static Func CreateUnfilteredFilter() {
+ return _ => true;
+ }
+
+ private static Func CreateTextFilter(string searchText) {
+ return kindGroup => kindGroup.Names.Any(a => a.Contains(searchText, StringComparison.CurrentCultureIgnoreCase));
+ }
+
+ private async Task ShowDetailsAsync(PackIconKindGroup icon, CancellationToken cancellationToken) {
+ DetailsViewModel.SelectedIcon = icon;
+ await Shell.Current.GoToAsync("Details", new Dictionary {
+ { "ViewModel", DetailsViewModel },
+ });
+ }
+}
diff --git a/Material.Icons.Maui.Demo/Material.Icons.Maui.Demo.csproj b/Material.Icons.Maui.Demo/Material.Icons.Maui.Demo.csproj
new file mode 100644
index 0000000..3a3a0fa
--- /dev/null
+++ b/Material.Icons.Maui.Demo/Material.Icons.Maui.Demo.csproj
@@ -0,0 +1,74 @@
+
+
+
+ net8.0-android;net8.0-ios;net8.0-maccatalyst
+ $(TargetFrameworks);net8.0-windows10.0.19041.0
+
+
+
+
+
+
+ Exe
+ Material.Icons.Maui.Demo
+ true
+ true
+ enable
+ enable
+
+
+ Material.Icons Demo
+
+
+ com.companyname.material.icons.maui.demo
+
+
+ 1.0
+ 1
+
+ 11.0
+ 13.1
+ 21.0
+ 10.0.17763.0
+ 10.0.17763.0
+ 6.5
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Material.Icons.Maui.Demo/MauiProgram.cs b/Material.Icons.Maui.Demo/MauiProgram.cs
new file mode 100644
index 0000000..78bef09
--- /dev/null
+++ b/Material.Icons.Maui.Demo/MauiProgram.cs
@@ -0,0 +1,46 @@
+using CommunityToolkit.Maui;
+using Microsoft.Extensions.Logging;
+
+using ReactiveUI;
+
+using Splat;
+using Splat.Microsoft.Extensions.DependencyInjection;
+using Splat.Microsoft.Extensions.Logging;
+
+namespace Material.Icons.Maui.Demo;
+
+public static class MauiProgram {
+ public static MauiApp CreateMauiApp() {
+ var builder = MauiApp.CreateBuilder();
+ builder
+ .UseMauiApp()
+ .UseMauiCommunityToolkit()
+ .ConfigureFonts(fonts => {
+ fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
+ fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
+ });
+
+ // Initialization of Splat and ReactiveUI
+ builder.Logging.AddSplat();
+ builder.Services.UseMicrosoftDependencyResolver();
+ Locator.CurrentMutable.InitializeSplat();
+ Locator.CurrentMutable.InitializeReactiveUI();
+
+ // ViewModels
+ builder.Services.AddSingleton();
+
+ // Views
+ builder.Services.AddSingleton();
+
+#if DEBUG
+ builder.Logging.AddDebug();
+#endif
+
+ var app = builder.Build();
+
+ // Post-initialization of Splat
+ app.Services.UseMicrosoftDependencyResolver();
+
+ return app;
+ }
+}
diff --git a/Material.Icons.Maui.Demo/PackIconKindGroup.cs b/Material.Icons.Maui.Demo/PackIconKindGroup.cs
new file mode 100644
index 0000000..51b0850
--- /dev/null
+++ b/Material.Icons.Maui.Demo/PackIconKindGroup.cs
@@ -0,0 +1,16 @@
+namespace Material.Icons.Maui.Demo;
+
+public class PackIconKindGroup {
+ public PackIconKindGroup(IEnumerable kinds) {
+ var sortedKinds = kinds.OrderBy(x => x, StringComparer.InvariantCultureIgnoreCase).ToArray();
+ if (sortedKinds.Length == 0)
+ throw new ArgumentException($"{nameof(kinds)} must contain at least one value");
+ Kind = Enum.Parse(sortedKinds[0]);
+ DisplayName = sortedKinds[0];
+ Names = sortedKinds;
+ }
+
+ public MaterialIconKind Kind { get; }
+ public string DisplayName { get; }
+ public string[] Names { get; }
+}
diff --git a/Material.Icons.Maui.Demo/Platforms/Android/AndroidManifest.xml b/Material.Icons.Maui.Demo/Platforms/Android/AndroidManifest.xml
new file mode 100644
index 0000000..e9937ad
--- /dev/null
+++ b/Material.Icons.Maui.Demo/Platforms/Android/AndroidManifest.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Material.Icons.Maui.Demo/Platforms/Android/MainActivity.cs b/Material.Icons.Maui.Demo/Platforms/Android/MainActivity.cs
new file mode 100644
index 0000000..25cb744
--- /dev/null
+++ b/Material.Icons.Maui.Demo/Platforms/Android/MainActivity.cs
@@ -0,0 +1,9 @@
+using Android.App;
+using Android.Content.PM;
+using Android.OS;
+
+namespace Material.Icons.Maui.Demo {
+ [Activity(Theme = "@style/Maui.SplashTheme", MainLauncher = true, LaunchMode = LaunchMode.SingleTop, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.Density)]
+ public class MainActivity : MauiAppCompatActivity {
+ }
+}
diff --git a/Material.Icons.Maui.Demo/Platforms/Android/MainApplication.cs b/Material.Icons.Maui.Demo/Platforms/Android/MainApplication.cs
new file mode 100644
index 0000000..ebd373c
--- /dev/null
+++ b/Material.Icons.Maui.Demo/Platforms/Android/MainApplication.cs
@@ -0,0 +1,13 @@
+using Android.App;
+using Android.Runtime;
+
+namespace Material.Icons.Maui.Demo {
+ [Application]
+ public class MainApplication : MauiApplication {
+ public MainApplication(IntPtr handle, JniHandleOwnership ownership)
+ : base(handle, ownership) {
+ }
+
+ protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
+ }
+}
diff --git a/Material.Icons.Maui.Demo/Platforms/Android/Resources/values/colors.xml b/Material.Icons.Maui.Demo/Platforms/Android/Resources/values/colors.xml
new file mode 100644
index 0000000..c04d749
--- /dev/null
+++ b/Material.Icons.Maui.Demo/Platforms/Android/Resources/values/colors.xml
@@ -0,0 +1,6 @@
+
+
+ #512BD4
+ #2B0B98
+ #2B0B98
+
\ No newline at end of file
diff --git a/Material.Icons.Maui.Demo/Platforms/MacCatalyst/AppDelegate.cs b/Material.Icons.Maui.Demo/Platforms/MacCatalyst/AppDelegate.cs
new file mode 100644
index 0000000..1c97ec3
--- /dev/null
+++ b/Material.Icons.Maui.Demo/Platforms/MacCatalyst/AppDelegate.cs
@@ -0,0 +1,8 @@
+using Foundation;
+
+namespace Material.Icons.Maui.Demo {
+ [Register("AppDelegate")]
+ public class AppDelegate : MauiUIApplicationDelegate {
+ protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
+ }
+}
diff --git a/Material.Icons.Maui.Demo/Platforms/MacCatalyst/Entitlements.plist b/Material.Icons.Maui.Demo/Platforms/MacCatalyst/Entitlements.plist
new file mode 100644
index 0000000..de4adc9
--- /dev/null
+++ b/Material.Icons.Maui.Demo/Platforms/MacCatalyst/Entitlements.plist
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+ com.apple.security.app-sandbox
+
+
+ com.apple.security.network.client
+
+
+
+
diff --git a/Material.Icons.Maui.Demo/Platforms/MacCatalyst/Info.plist b/Material.Icons.Maui.Demo/Platforms/MacCatalyst/Info.plist
new file mode 100644
index 0000000..7268977
--- /dev/null
+++ b/Material.Icons.Maui.Demo/Platforms/MacCatalyst/Info.plist
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ UIDeviceFamily
+
+ 2
+
+ UIRequiredDeviceCapabilities
+
+ arm64
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UISupportedInterfaceOrientations~ipad
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationPortraitUpsideDown
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ XSAppIconAssets
+ Assets.xcassets/appicon.appiconset
+
+
diff --git a/Material.Icons.Maui.Demo/Platforms/MacCatalyst/Program.cs b/Material.Icons.Maui.Demo/Platforms/MacCatalyst/Program.cs
new file mode 100644
index 0000000..70149bc
--- /dev/null
+++ b/Material.Icons.Maui.Demo/Platforms/MacCatalyst/Program.cs
@@ -0,0 +1,14 @@
+using ObjCRuntime;
+
+using UIKit;
+
+namespace Material.Icons.Maui.Demo {
+ public class Program {
+ // 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));
+ }
+ }
+}
diff --git a/Material.Icons.Maui.Demo/Platforms/Tizen/Main.cs b/Material.Icons.Maui.Demo/Platforms/Tizen/Main.cs
new file mode 100644
index 0000000..4b19712
--- /dev/null
+++ b/Material.Icons.Maui.Demo/Platforms/Tizen/Main.cs
@@ -0,0 +1,15 @@
+using System;
+
+using Microsoft.Maui;
+using Microsoft.Maui.Hosting;
+
+namespace Material.Icons.Maui.Demo {
+ internal class Program : MauiApplication {
+ protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
+
+ static void Main(string[] args) {
+ var app = new Program();
+ app.Run(args);
+ }
+ }
+}
diff --git a/Material.Icons.Maui.Demo/Platforms/Tizen/tizen-manifest.xml b/Material.Icons.Maui.Demo/Platforms/Tizen/tizen-manifest.xml
new file mode 100644
index 0000000..3a7dd2d
--- /dev/null
+++ b/Material.Icons.Maui.Demo/Platforms/Tizen/tizen-manifest.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+ maui-appicon-placeholder
+
+
+
+
+ http://tizen.org/privilege/internet
+
+
+
+
\ No newline at end of file
diff --git a/Material.Icons.Maui.Demo/Platforms/Windows/App.xaml b/Material.Icons.Maui.Demo/Platforms/Windows/App.xaml
new file mode 100644
index 0000000..0ef0afd
--- /dev/null
+++ b/Material.Icons.Maui.Demo/Platforms/Windows/App.xaml
@@ -0,0 +1,8 @@
+
+
+
diff --git a/Material.Icons.Maui.Demo/Platforms/Windows/App.xaml.cs b/Material.Icons.Maui.Demo/Platforms/Windows/App.xaml.cs
new file mode 100644
index 0000000..7e6f54e
--- /dev/null
+++ b/Material.Icons.Maui.Demo/Platforms/Windows/App.xaml.cs
@@ -0,0 +1,22 @@
+using Microsoft.UI.Xaml;
+
+// To learn more about WinUI, the WinUI project structure,
+// and more about our project templates, see: http://aka.ms/winui-project-info.
+
+namespace Material.Icons.Maui.Demo.WinUI {
+ ///
+ /// Provides application-specific behavior to supplement the default Application class.
+ ///
+ public partial class App : MauiWinUIApplication {
+ ///
+ /// Initializes the singleton application object. This is the first line of authored code
+ /// executed, and as such is the logical equivalent of main() or WinMain().
+ ///
+ public App() {
+ this.InitializeComponent();
+ }
+
+ protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
+ }
+
+}
diff --git a/Material.Icons.Maui.Demo/Platforms/Windows/Package.appxmanifest b/Material.Icons.Maui.Demo/Platforms/Windows/Package.appxmanifest
new file mode 100644
index 0000000..8960aa1
--- /dev/null
+++ b/Material.Icons.Maui.Demo/Platforms/Windows/Package.appxmanifest
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+ $placeholder$
+ User Name
+ $placeholder$.png
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Material.Icons.Maui.Demo/Platforms/Windows/app.manifest b/Material.Icons.Maui.Demo/Platforms/Windows/app.manifest
new file mode 100644
index 0000000..ea951c4
--- /dev/null
+++ b/Material.Icons.Maui.Demo/Platforms/Windows/app.manifest
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+ true/PM
+ PerMonitorV2, PerMonitor
+
+
+
diff --git a/Material.Icons.Maui.Demo/Platforms/iOS/AppDelegate.cs b/Material.Icons.Maui.Demo/Platforms/iOS/AppDelegate.cs
new file mode 100644
index 0000000..1c97ec3
--- /dev/null
+++ b/Material.Icons.Maui.Demo/Platforms/iOS/AppDelegate.cs
@@ -0,0 +1,8 @@
+using Foundation;
+
+namespace Material.Icons.Maui.Demo {
+ [Register("AppDelegate")]
+ public class AppDelegate : MauiUIApplicationDelegate {
+ protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
+ }
+}
diff --git a/Material.Icons.Maui.Demo/Platforms/iOS/Info.plist b/Material.Icons.Maui.Demo/Platforms/iOS/Info.plist
new file mode 100644
index 0000000..0004a4f
--- /dev/null
+++ b/Material.Icons.Maui.Demo/Platforms/iOS/Info.plist
@@ -0,0 +1,32 @@
+
+
+
+
+ LSRequiresIPhoneOS
+
+ UIDeviceFamily
+
+ 1
+ 2
+
+ UIRequiredDeviceCapabilities
+
+ arm64
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UISupportedInterfaceOrientations~ipad
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationPortraitUpsideDown
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ XSAppIconAssets
+ Assets.xcassets/appicon.appiconset
+
+
diff --git a/Material.Icons.Maui.Demo/Platforms/iOS/Program.cs b/Material.Icons.Maui.Demo/Platforms/iOS/Program.cs
new file mode 100644
index 0000000..70149bc
--- /dev/null
+++ b/Material.Icons.Maui.Demo/Platforms/iOS/Program.cs
@@ -0,0 +1,14 @@
+using ObjCRuntime;
+
+using UIKit;
+
+namespace Material.Icons.Maui.Demo {
+ public class Program {
+ // 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));
+ }
+ }
+}
diff --git a/Material.Icons.Maui.Demo/Platforms/iOS/Resources/PrivacyInfo.xcprivacy b/Material.Icons.Maui.Demo/Platforms/iOS/Resources/PrivacyInfo.xcprivacy
new file mode 100644
index 0000000..24ab3b4
--- /dev/null
+++ b/Material.Icons.Maui.Demo/Platforms/iOS/Resources/PrivacyInfo.xcprivacy
@@ -0,0 +1,51 @@
+
+
+
+
+
+ NSPrivacyAccessedAPITypes
+
+
+ NSPrivacyAccessedAPIType
+ NSPrivacyAccessedAPICategoryFileTimestamp
+ NSPrivacyAccessedAPITypeReasons
+
+ C617.1
+
+
+
+ NSPrivacyAccessedAPIType
+ NSPrivacyAccessedAPICategorySystemBootTime
+ NSPrivacyAccessedAPITypeReasons
+
+ 35F9.1
+
+
+
+ NSPrivacyAccessedAPIType
+ NSPrivacyAccessedAPICategoryDiskSpace
+ NSPrivacyAccessedAPITypeReasons
+
+ E174.1
+
+
+
+
+
+
diff --git a/Material.Icons.Maui.Demo/Properties/launchSettings.json b/Material.Icons.Maui.Demo/Properties/launchSettings.json
new file mode 100644
index 0000000..edf8aad
--- /dev/null
+++ b/Material.Icons.Maui.Demo/Properties/launchSettings.json
@@ -0,0 +1,8 @@
+{
+ "profiles": {
+ "Windows Machine": {
+ "commandName": "MsixPackage",
+ "nativeDebugging": false
+ }
+ }
+}
\ No newline at end of file
diff --git a/Material.Icons.Maui.Demo/Resources/AppIcon/appicon.svg b/Material.Icons.Maui.Demo/Resources/AppIcon/appicon.svg
new file mode 100644
index 0000000..9d63b65
--- /dev/null
+++ b/Material.Icons.Maui.Demo/Resources/AppIcon/appicon.svg
@@ -0,0 +1,4 @@
+
+
\ No newline at end of file
diff --git a/Material.Icons.Maui.Demo/Resources/AppIcon/appiconfg.svg b/Material.Icons.Maui.Demo/Resources/AppIcon/appiconfg.svg
new file mode 100644
index 0000000..21dfb25
--- /dev/null
+++ b/Material.Icons.Maui.Demo/Resources/AppIcon/appiconfg.svg
@@ -0,0 +1,8 @@
+
+
+
\ No newline at end of file
diff --git a/Material.Icons.Maui.Demo/Resources/Fonts/OpenSans-Regular.ttf b/Material.Icons.Maui.Demo/Resources/Fonts/OpenSans-Regular.ttf
new file mode 100644
index 0000000..2291fcb
Binary files /dev/null and b/Material.Icons.Maui.Demo/Resources/Fonts/OpenSans-Regular.ttf differ
diff --git a/Material.Icons.Maui.Demo/Resources/Fonts/OpenSans-Semibold.ttf b/Material.Icons.Maui.Demo/Resources/Fonts/OpenSans-Semibold.ttf
new file mode 100644
index 0000000..3cbe2f8
Binary files /dev/null and b/Material.Icons.Maui.Demo/Resources/Fonts/OpenSans-Semibold.ttf differ
diff --git a/Material.Icons.Maui.Demo/Resources/Images/dotnet_bot.png b/Material.Icons.Maui.Demo/Resources/Images/dotnet_bot.png
new file mode 100644
index 0000000..f93ce02
Binary files /dev/null and b/Material.Icons.Maui.Demo/Resources/Images/dotnet_bot.png differ
diff --git a/Material.Icons.Maui.Demo/Resources/Raw/AboutAssets.txt b/Material.Icons.Maui.Demo/Resources/Raw/AboutAssets.txt
new file mode 100644
index 0000000..89dc758
--- /dev/null
+++ b/Material.Icons.Maui.Demo/Resources/Raw/AboutAssets.txt
@@ -0,0 +1,15 @@
+Any raw assets you want to be deployed with your application can be placed in
+this directory (and child directories). Deployment of the asset to your application
+is automatically handled by the following `MauiAsset` Build Action within your `.csproj`.
+
+
+
+These files will be deployed with your package and will be accessible using Essentials:
+
+ async Task LoadMauiAsset()
+ {
+ using var stream = await FileSystem.OpenAppPackageFileAsync("AboutAssets.txt");
+ using var reader = new StreamReader(stream);
+
+ var contents = reader.ReadToEnd();
+ }
diff --git a/Material.Icons.Maui.Demo/Resources/Splash/splash.svg b/Material.Icons.Maui.Demo/Resources/Splash/splash.svg
new file mode 100644
index 0000000..21dfb25
--- /dev/null
+++ b/Material.Icons.Maui.Demo/Resources/Splash/splash.svg
@@ -0,0 +1,8 @@
+
+
+
\ No newline at end of file
diff --git a/Material.Icons.Maui.Demo/Resources/Styles/Colors.xaml b/Material.Icons.Maui.Demo/Resources/Styles/Colors.xaml
new file mode 100644
index 0000000..30307a5
--- /dev/null
+++ b/Material.Icons.Maui.Demo/Resources/Styles/Colors.xaml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+ #512BD4
+ #ac99ea
+ #242424
+ #DFD8F7
+ #9880e5
+ #2B0B98
+
+ White
+ Black
+ #D600AA
+ #190649
+ #1f1f1f
+
+ #E1E1E1
+ #C8C8C8
+ #ACACAC
+ #919191
+ #6E6E6E
+ #404040
+ #212121
+ #141414
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Material.Icons.Maui.Demo/Resources/Styles/Styles.xaml b/Material.Icons.Maui.Demo/Resources/Styles/Styles.xaml
new file mode 100644
index 0000000..6641e3a
--- /dev/null
+++ b/Material.Icons.Maui.Demo/Resources/Styles/Styles.xaml
@@ -0,0 +1,427 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Material.Icons.Maui/AssemblyInfo.cs b/Material.Icons.Maui/AssemblyInfo.cs
new file mode 100644
index 0000000..23abec9
--- /dev/null
+++ b/Material.Icons.Maui/AssemblyInfo.cs
@@ -0,0 +1,3 @@
+[assembly: XmlnsDefinition("http://schemas.skproch/material/icons/2024", "Material.Icons.Maui")]
+
+[assembly: Microsoft.Maui.Controls.XmlnsPrefix("http://schemas.skproch/material/icons/2024", "material")]
diff --git a/Material.Icons.Maui/Controls.cs b/Material.Icons.Maui/Controls.cs
new file mode 100644
index 0000000..2b75d21
--- /dev/null
+++ b/Material.Icons.Maui/Controls.cs
@@ -0,0 +1,5 @@
+namespace Material.Icons.Maui;
+
+public static class Controls {
+ public static void Init() { }
+}
diff --git a/Material.Icons.Maui/Material.Icons.Maui.csproj b/Material.Icons.Maui/Material.Icons.Maui.csproj
new file mode 100644
index 0000000..45cbd4a
--- /dev/null
+++ b/Material.Icons.Maui/Material.Icons.Maui.csproj
@@ -0,0 +1,42 @@
+
+
+
+ net8.0-android;net8.0-ios;net8.0-maccatalyst
+ $(TargetFrameworks);net8.0-windows10.0.19041.0
+
+
+ true
+ true
+ enable
+ enable
+
+ 11.0
+ 13.1
+ 21.0
+ 10.0.17763.0
+ 10.0.17763.0
+ 6.5
+
+
+
+
+
+
+
+
+
+
+
+
+
+ MSBuild:Compile
+
+
+
+
+
+ MSBuild:Compile
+
+
+
+
diff --git a/Material.Icons.Maui/MaterialIcon.xaml b/Material.Icons.Maui/MaterialIcon.xaml
new file mode 100644
index 0000000..f41bdff
--- /dev/null
+++ b/Material.Icons.Maui/MaterialIcon.xaml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
diff --git a/Material.Icons.Maui/MaterialIcon.xaml.cs b/Material.Icons.Maui/MaterialIcon.xaml.cs
new file mode 100644
index 0000000..2045e0c
--- /dev/null
+++ b/Material.Icons.Maui/MaterialIcon.xaml.cs
@@ -0,0 +1,87 @@
+using System.ComponentModel;
+using System.Diagnostics;
+
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Abstractions;
+using Microsoft.Maui.Controls.Shapes;
+
+namespace Material.Icons.Maui;
+
+public partial class MaterialIcon {
+ private static readonly BindablePropertyKey DataPropertyKey
+ = BindableProperty.CreateReadOnly(nameof(Data), typeof(Geometry), typeof(MaterialIcon), null);
+
+ public static readonly BindableProperty KindProperty
+ = BindableProperty.Create(nameof(Kind), typeof(MaterialIconKind?), typeof(MaterialIcon),
+ propertyChanged: KindPropertyChangedCallback);
+
+ public static readonly BindableProperty ForegroundProperty
+ = BindableProperty.Create(nameof(Foreground), typeof(Brush), typeof(MaterialIcon));
+
+ public static readonly BindableProperty DataProperty = DataPropertyKey.BindableProperty;
+
+ private readonly PathGeometryConverter _converter = new();
+
+ private ILogger? _logger;
+
+ public MaterialIcon()
+ {
+ InitializeComponent();
+ }
+
+ ///
+ /// Gets or sets the brush used to draw the icon.
+ ///
+ [TypeConverter(typeof(BrushTypeConverter))]
+ public Brush? Foreground {
+ get => (Brush?)GetValue(ForegroundProperty);
+ set => SetValue(ForegroundProperty, value);
+ }
+
+ ///
+ /// Gets or sets the icon to display.
+ ///
+ public MaterialIconKind? Kind {
+ get => (MaterialIconKind?)GetValue(KindProperty);
+ set => SetValue(KindProperty, value);
+ }
+
+ ///
+ /// Gets the icon path data for the current .
+ ///
+ public Geometry? Data => (Geometry?)GetValue(DataProperty);
+
+ private ILogger Logger => _logger ??= GetLogger() ?? NullLogger.Instance;
+
+ private static void KindPropertyChangedCallback(BindableObject bindable, object oldValue, object newValue) {
+ ((MaterialIcon)bindable).UpdateData((MaterialIconKind?)newValue);
+ }
+
+ private MaterialIconDataProvider GetProvider() {
+ return IPlatformApplication.Current?.Services.GetService()
+ ?? MaterialIconDataProvider.Instance;
+ }
+
+ private ILogger? GetLogger() {
+ return IPlatformApplication.Current?.Services.GetService>();
+ }
+
+ private Geometry? GetGeometry(MaterialIconKind? kind) {
+ try {
+ Debug.WriteLine($"Getting geometry for icon {kind}");
+ var result = kind is not null
+ ? (Geometry?)_converter.ConvertFromInvariantString(GetProvider().ProvideData(kind.Value))
+ : null;
+ Debug.WriteLine($"Got geometry for icon {kind}");
+ return result;
+ }
+ catch (Exception ex) {
+ Logger.LogError(ex, "Failed to get geometry for icon {Kind}", kind);
+ return null;
+ }
+ }
+
+ private void UpdateData(MaterialIconKind? kind) {
+ SetValue(DataPropertyKey, GetGeometry(kind));
+ }
+}
diff --git a/Material.Icons.Maui/MaterialIconExt.cs b/Material.Icons.Maui/MaterialIconExt.cs
new file mode 100644
index 0000000..a55f344
--- /dev/null
+++ b/Material.Icons.Maui/MaterialIconExt.cs
@@ -0,0 +1,36 @@
+
+
+namespace Material.Icons.Maui;
+
+public class MaterialIconExt : IMarkupExtension {
+
+ public MaterialIconExt() { }
+
+ public MaterialIconExt(MaterialIconKind kind) {
+ Kind = kind;
+ }
+
+ public MaterialIconExt(MaterialIconKind kind, double size) {
+ Kind = kind;
+ Size = size;
+ }
+
+ public MaterialIconKind Kind { get; set; }
+
+ public double? Size { get; set; }
+
+ public MaterialIcon ProvideValue(IServiceProvider serviceProvider) {
+ var result = new MaterialIcon { Kind = Kind };
+
+ if (Size.HasValue) {
+ result.WidthRequest = Size.Value;
+ result.HeightRequest = Size.Value;
+ }
+
+ return result;
+ }
+
+ object IMarkupExtension.ProvideValue(IServiceProvider serviceProvider) {
+ return ProvideValue(serviceProvider);
+ }
+}
diff --git a/Material.Icons.Maui/MaterialIconGeometryExtension.cs b/Material.Icons.Maui/MaterialIconGeometryExtension.cs
new file mode 100644
index 0000000..a6c6c3e
--- /dev/null
+++ b/Material.Icons.Maui/MaterialIconGeometryExtension.cs
@@ -0,0 +1,34 @@
+
+using Microsoft.Maui.Controls.Shapes;
+
+namespace Material.Icons.Maui;
+
+public class MaterialIconGeometryExtension : IMarkupExtension {
+ private readonly PathGeometryConverter _converter = new();
+
+ public MaterialIconGeometryExtension() { }
+
+ public MaterialIconGeometryExtension(MaterialIconKind kind) {
+ Kind = kind;
+ }
+
+ public MaterialIconKind Kind { get; set; }
+
+ public Geometry ProvideValue(IServiceProvider serviceProvider) {
+ var provider =
+ serviceProvider.GetService()
+ ?? MaterialIconDataProvider.Instance;
+ var data = provider.ProvideData(Kind);
+ var geometry = (Geometry?)_converter.ConvertFromInvariantString(data);
+ if (geometry == null) {
+ var li = (serviceProvider.GetService(typeof(IXmlLineInfoProvider)) is IXmlLineInfoProvider lip) ? lip.XmlLineInfo : new XmlLineInfo();
+ throw new XamlParseException($"Geometry data not parsable for icon {Kind}.", li);
+ }
+
+ return geometry;
+ }
+
+ object IMarkupExtension.ProvideValue(IServiceProvider serviceProvider) {
+ return ProvideValue(serviceProvider);
+ }
+}
diff --git a/Material.Icons.Maui/Platforms/Android/PlatformClass1.cs b/Material.Icons.Maui/Platforms/Android/PlatformClass1.cs
new file mode 100644
index 0000000..5312280
--- /dev/null
+++ b/Material.Icons.Maui/Platforms/Android/PlatformClass1.cs
@@ -0,0 +1,5 @@
+namespace Material.Icons.Maui {
+ // All the code in this file is only included on Android.
+ public class PlatformClass1 {
+ }
+}
diff --git a/Material.Icons.Maui/Platforms/MacCatalyst/PlatformClass1.cs b/Material.Icons.Maui/Platforms/MacCatalyst/PlatformClass1.cs
new file mode 100644
index 0000000..10d298e
--- /dev/null
+++ b/Material.Icons.Maui/Platforms/MacCatalyst/PlatformClass1.cs
@@ -0,0 +1,5 @@
+namespace Material.Icons.Maui {
+ // All the code in this file is only included on Mac Catalyst.
+ public class PlatformClass1 {
+ }
+}
diff --git a/Material.Icons.Maui/Platforms/Tizen/PlatformClass1.cs b/Material.Icons.Maui/Platforms/Tizen/PlatformClass1.cs
new file mode 100644
index 0000000..816246f
--- /dev/null
+++ b/Material.Icons.Maui/Platforms/Tizen/PlatformClass1.cs
@@ -0,0 +1,7 @@
+using System;
+
+namespace Material.Icons.Maui {
+ // All the code in this file is only included on Tizen.
+ public class PlatformClass1 {
+ }
+}
\ No newline at end of file
diff --git a/Material.Icons.Maui/Platforms/Windows/PlatformClass1.cs b/Material.Icons.Maui/Platforms/Windows/PlatformClass1.cs
new file mode 100644
index 0000000..be2302e
--- /dev/null
+++ b/Material.Icons.Maui/Platforms/Windows/PlatformClass1.cs
@@ -0,0 +1,5 @@
+namespace Material.Icons.Maui {
+ // All the code in this file is only included on Windows.
+ public class PlatformClass1 {
+ }
+}
diff --git a/Material.Icons.Maui/Platforms/iOS/PlatformClass1.cs b/Material.Icons.Maui/Platforms/iOS/PlatformClass1.cs
new file mode 100644
index 0000000..825053f
--- /dev/null
+++ b/Material.Icons.Maui/Platforms/iOS/PlatformClass1.cs
@@ -0,0 +1,5 @@
+namespace Material.Icons.Maui {
+ // All the code in this file is only included on iOS.
+ public class PlatformClass1 {
+ }
+}
diff --git a/Material.Icons.sln b/Material.Icons.sln
index 6ef7f67..e0cf3a5 100644
--- a/Material.Icons.sln
+++ b/Material.Icons.sln
@@ -19,6 +19,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Material.Icons.WinUI3", "Ma
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Material.Icons.WinUI3.Demo", "Material.Icons.WinUI3.Demo\Material.Icons.WinUI3.Demo.csproj", "{5E59EDA4-2220-41ED-9F84-14019367EAEB}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Material.Icons.Maui", "Material.Icons.Maui\Material.Icons.Maui.csproj", "{967C14EF-DAC0-486B-AA72-8986C515E58C}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Material.Icons.Maui.Demo", "Material.Icons.Maui.Demo\Material.Icons.Maui.Demo.csproj", "{9BDCFF13-DBFE-4A51-914C-7D4127E25869}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -131,6 +135,46 @@ Global
{5E59EDA4-2220-41ED-9F84-14019367EAEB}.Release|x86.ActiveCfg = Release|x86
{5E59EDA4-2220-41ED-9F84-14019367EAEB}.Release|x86.Build.0 = Release|x86
{5E59EDA4-2220-41ED-9F84-14019367EAEB}.Release|x86.Deploy.0 = Release|x86
+ {967C14EF-DAC0-486B-AA72-8986C515E58C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {967C14EF-DAC0-486B-AA72-8986C515E58C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {967C14EF-DAC0-486B-AA72-8986C515E58C}.Debug|ARM64.ActiveCfg = Debug|Any CPU
+ {967C14EF-DAC0-486B-AA72-8986C515E58C}.Debug|ARM64.Build.0 = Debug|Any CPU
+ {967C14EF-DAC0-486B-AA72-8986C515E58C}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {967C14EF-DAC0-486B-AA72-8986C515E58C}.Debug|x64.Build.0 = Debug|Any CPU
+ {967C14EF-DAC0-486B-AA72-8986C515E58C}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {967C14EF-DAC0-486B-AA72-8986C515E58C}.Debug|x86.Build.0 = Debug|Any CPU
+ {967C14EF-DAC0-486B-AA72-8986C515E58C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {967C14EF-DAC0-486B-AA72-8986C515E58C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {967C14EF-DAC0-486B-AA72-8986C515E58C}.Release|ARM64.ActiveCfg = Release|Any CPU
+ {967C14EF-DAC0-486B-AA72-8986C515E58C}.Release|ARM64.Build.0 = Release|Any CPU
+ {967C14EF-DAC0-486B-AA72-8986C515E58C}.Release|x64.ActiveCfg = Release|Any CPU
+ {967C14EF-DAC0-486B-AA72-8986C515E58C}.Release|x64.Build.0 = Release|Any CPU
+ {967C14EF-DAC0-486B-AA72-8986C515E58C}.Release|x86.ActiveCfg = Release|Any CPU
+ {967C14EF-DAC0-486B-AA72-8986C515E58C}.Release|x86.Build.0 = Release|Any CPU
+ {9BDCFF13-DBFE-4A51-914C-7D4127E25869}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {9BDCFF13-DBFE-4A51-914C-7D4127E25869}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {9BDCFF13-DBFE-4A51-914C-7D4127E25869}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
+ {9BDCFF13-DBFE-4A51-914C-7D4127E25869}.Debug|ARM64.ActiveCfg = Debug|Any CPU
+ {9BDCFF13-DBFE-4A51-914C-7D4127E25869}.Debug|ARM64.Build.0 = Debug|Any CPU
+ {9BDCFF13-DBFE-4A51-914C-7D4127E25869}.Debug|ARM64.Deploy.0 = Debug|Any CPU
+ {9BDCFF13-DBFE-4A51-914C-7D4127E25869}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {9BDCFF13-DBFE-4A51-914C-7D4127E25869}.Debug|x64.Build.0 = Debug|Any CPU
+ {9BDCFF13-DBFE-4A51-914C-7D4127E25869}.Debug|x64.Deploy.0 = Debug|Any CPU
+ {9BDCFF13-DBFE-4A51-914C-7D4127E25869}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {9BDCFF13-DBFE-4A51-914C-7D4127E25869}.Debug|x86.Build.0 = Debug|Any CPU
+ {9BDCFF13-DBFE-4A51-914C-7D4127E25869}.Debug|x86.Deploy.0 = Debug|Any CPU
+ {9BDCFF13-DBFE-4A51-914C-7D4127E25869}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {9BDCFF13-DBFE-4A51-914C-7D4127E25869}.Release|Any CPU.Build.0 = Release|Any CPU
+ {9BDCFF13-DBFE-4A51-914C-7D4127E25869}.Release|Any CPU.Deploy.0 = Release|Any CPU
+ {9BDCFF13-DBFE-4A51-914C-7D4127E25869}.Release|ARM64.ActiveCfg = Release|Any CPU
+ {9BDCFF13-DBFE-4A51-914C-7D4127E25869}.Release|ARM64.Build.0 = Release|Any CPU
+ {9BDCFF13-DBFE-4A51-914C-7D4127E25869}.Release|ARM64.Deploy.0 = Release|Any CPU
+ {9BDCFF13-DBFE-4A51-914C-7D4127E25869}.Release|x64.ActiveCfg = Release|Any CPU
+ {9BDCFF13-DBFE-4A51-914C-7D4127E25869}.Release|x64.Build.0 = Release|Any CPU
+ {9BDCFF13-DBFE-4A51-914C-7D4127E25869}.Release|x64.Deploy.0 = Release|Any CPU
+ {9BDCFF13-DBFE-4A51-914C-7D4127E25869}.Release|x86.ActiveCfg = Release|Any CPU
+ {9BDCFF13-DBFE-4A51-914C-7D4127E25869}.Release|x86.Build.0 = Release|Any CPU
+ {9BDCFF13-DBFE-4A51-914C-7D4127E25869}.Release|x86.Deploy.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/build/_build.csproj.DotSettings b/build/_build.csproj.DotSettings
index 7bc2848..337271d 100644
--- a/build/_build.csproj.DotSettings
+++ b/build/_build.csproj.DotSettings
@@ -16,6 +16,8 @@
False
<Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
<Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
+ <Policy><Descriptor Staticness="Instance" AccessRightKinds="Private" Description="Instance fields (private)"><ElementKinds><Kind Name="FIELD" /><Kind Name="READONLY_FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></Policy>
+ <Policy><Descriptor Staticness="Static" AccessRightKinds="Private" Description="Static fields (private)"><ElementKinds><Kind Name="FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></Policy>
True
True
True
@@ -24,4 +26,5 @@
True
True
True
- True
+ True
+ True