├── .github └── FUNDING.yml ├── .gitignore ├── LICENSE ├── PleasantUI.sln ├── PleasantUIIcon.png ├── README.md ├── build └── Package.props ├── designer └── PleasantUI.Designer │ ├── App.axaml │ ├── App.axaml.cs │ ├── PleasantUI.Designer.csproj │ ├── Program.cs │ └── app.manifest ├── generators └── PleasantUI.MaterialIcons.SourceGenerator │ ├── MaterialIconsSourceGenerator.cs │ ├── PleasantUI.MaterialIcons.SourceGenerator.csproj │ ├── Properties │ └── launchSettings.json │ └── StringExtensions.cs ├── global.json ├── samples ├── PleasantUI.Example.Android │ ├── AndroidManifest.xml │ ├── App.axaml │ ├── App.axaml.cs │ ├── Assets │ │ └── Icons.axaml │ ├── Icon.png │ ├── MainActivity.cs │ ├── PleasantMainView.axaml │ ├── PleasantMainView.axaml.cs │ ├── PleasantUI.Example.Android.csproj │ ├── Properties │ │ └── AndroidManifest.xml │ └── Resources │ │ ├── AboutResources.txt │ │ ├── drawable-night-v31 │ │ └── avalonia_anim.xml │ │ ├── drawable-v31 │ │ └── avalonia_anim.xml │ │ ├── drawable │ │ └── splash_screen.xml │ │ ├── values-night │ │ └── colors.xml │ │ ├── values-v31 │ │ └── styles.xml │ │ └── values │ │ ├── colors.xml │ │ └── styles.xml ├── PleasantUI.Example.Browser │ ├── App.axaml │ ├── App.axaml.cs │ ├── PleasantMainView.axaml │ ├── PleasantMainView.axaml.cs │ ├── PleasantUI.Example.Browser.csproj │ ├── Program.cs │ ├── Properties │ │ ├── AssemblyInfo.cs │ │ └── launchSettings.json │ ├── runtimeconfig.template.json │ └── wwwroot │ │ ├── app.css │ │ ├── favicon.ico │ │ ├── index.html │ │ └── main.js ├── PleasantUI.Example.Desktop │ ├── App.axaml │ ├── App.axaml.cs │ ├── MainWindow.axaml │ ├── MainWindow.axaml.cs │ ├── PleasantUI.Example.Desktop.csproj │ ├── PleasantUIIcon.ico │ ├── Program.cs │ └── app.manifest └── PleasantUI.Example │ ├── Assets │ └── Images.axaml │ ├── DataTemplates │ └── ControlPageCardItemTemplate.axaml │ ├── Factories │ └── ControlPageCardsFactory.cs │ ├── Interfaces │ └── IPage.cs │ ├── Logging │ └── Logging │ │ ├── LoggerExtensions.cs │ │ ├── PleasantLogger.cs │ │ └── SerilogSink.cs │ ├── MainView.axaml │ ├── MainView.axaml.cs │ ├── Models │ ├── ControlPageCard.cs │ └── DataModel.cs │ ├── Pages │ ├── BasicControls │ │ ├── ButtonPage.cs │ │ ├── CalendarPage.cs │ │ ├── CarouselPage.cs │ │ ├── CheckBoxPage.cs │ │ ├── ComboBoxPage.cs │ │ ├── DataGridPage.cs │ │ ├── HomePage.cs │ │ ├── ProgressBarPage.cs │ │ ├── SliderPage.cs │ │ └── TextBoxPage.cs │ ├── PleasantControls │ │ ├── InformationBlockPage.cs │ │ ├── OptionsDisplayItemPage.cs │ │ ├── PleasantSnackbarPage.cs │ │ ├── PleasantTabViewPage.cs │ │ └── ProgressPage.cs │ └── ToolKit │ │ └── MessageBoxPage.cs │ ├── PleasantUI.Example.csproj │ ├── PleasantUIExampleApp.cs │ ├── Properties │ └── Localizations │ │ ├── App.Designer.cs │ │ ├── App.resx │ │ ├── App.ru.resx │ │ ├── Library.Designer.cs │ │ ├── Library.resx │ │ └── Library.ru.resx │ ├── Structures │ └── Language.cs │ ├── ViewModels │ ├── AppViewModel.cs │ └── Pages │ │ ├── ControlPages │ │ ├── DataGridViewModel.cs │ │ └── ProgressRingViewModel.cs │ │ └── SettingsViewModel.cs │ └── Views │ ├── AboutView.axaml │ ├── AboutView.axaml.cs │ ├── HomeView.axaml │ ├── HomeView.axaml.cs │ ├── Pages │ ├── ControlPages │ │ ├── ButtonPageView.axaml │ │ ├── ButtonPageView.axaml.cs │ │ ├── CalendarPageView.axaml │ │ ├── CalendarPageView.axaml.cs │ │ ├── CarouselPageView.axaml │ │ ├── CarouselPageView.axaml.cs │ │ ├── CheckBoxPageView.axaml │ │ ├── CheckBoxPageView.axaml.cs │ │ ├── ComboBoxPageView.axaml │ │ ├── ComboBoxPageView.axaml.cs │ │ ├── DataGridPageView.axaml │ │ ├── DataGridPageView.axaml.cs │ │ ├── ProgressBarPageView.axaml │ │ ├── ProgressBarPageView.axaml.cs │ │ ├── SliderPageView.axaml │ │ ├── SliderPageView.axaml.cs │ │ ├── TextBoxPageView.axaml │ │ └── TextBoxPageView.axaml.cs │ ├── HomePageView.axaml │ ├── HomePageView.axaml.cs │ ├── PleasantControlPages │ │ ├── InformationBlockPageView.axaml │ │ ├── InformationBlockPageView.axaml.cs │ │ ├── OptionsDisplayItemPageView.axaml │ │ ├── OptionsDisplayItemPageView.axaml.cs │ │ ├── PleasantSnackbarPageView.axaml │ │ ├── PleasantSnackbarPageView.axaml.cs │ │ ├── PleasantTabViewPageView.axaml │ │ ├── PleasantTabViewPageView.axaml.cs │ │ ├── ProgressRingPageView.axaml │ │ └── ProgressRingPageView.axaml.cs │ └── ToolKitPages │ │ ├── MessageBoxPageView.axaml │ │ └── MessageBoxPageView.axaml.cs │ ├── SettingsView.axaml │ └── SettingsView.axaml.cs └── src ├── PleasantUI.DataGrid ├── DataGrid.axaml └── PleasantUI.DataGrid.csproj ├── PleasantUI.MaterialIcons ├── MaterialIcons.cs ├── PleasantUI.MaterialIcons.csproj └── Properties │ └── AssemblyInfo.cs ├── PleasantUI.ToolKit ├── ColorPickerWindow.axaml ├── ColorPickerWindow.axaml.cs ├── Commands │ ├── IEditorCommand.cs │ └── ThemeEditor │ │ ├── ColorChangeCommand.cs │ │ ├── ThemeChangeCommand.cs │ │ └── ThemeNameChangeCommand.cs ├── Controls │ └── PleasantColorView │ │ └── PleasantColorView.cs ├── Converters │ └── ColorPickerConverters.cs ├── DataTemplates │ └── ThemeColorItemTemplate.axaml ├── MessageBox.axaml ├── MessageBox.axaml.cs ├── Messages │ ├── AsyncClipboardSetColorMessage.cs │ ├── AsyncRequestClipboardColorMessage.cs │ ├── AsyncRequestColorMessage.cs │ └── ColorChangedMessage.cs ├── Models │ └── ThemeColor.cs ├── PleasantUI.ToolKit.csproj ├── PleasantUIToolKit.axaml ├── Styling │ └── ControlThemes │ │ └── BasicControls │ │ ├── ColorPreviewer.axaml │ │ ├── ColorSlider.axaml │ │ ├── ColorSpectrum.axaml │ │ └── ColorView.axaml ├── ThemeEditorWindow.axaml ├── ThemeEditorWindow.axaml.cs ├── UserControls │ ├── ThemePreview.axaml │ └── ThemePreview.axaml.cs └── ViewModels │ └── ThemeEditorViewModel.cs └── PleasantUI ├── Assets └── IconGeometries.axaml ├── Behaviors └── ShadowBehavior.cs ├── Controls ├── BackdropBlurControl │ └── BackdropBlurControl.cs ├── Chrome │ ├── PleasantCaptionButtons.cs │ └── PleasantTitleBar.cs ├── ContentDialog │ └── ContentDialog.cs ├── Flyout │ ├── PleasantFlyout.cs │ ├── PleasantMenuFlyout.cs │ └── Presenters │ │ ├── PleasantFlyoutPresenter.cs │ │ └── PleasantMenuFlyoutPresenter.cs ├── InformationBlock │ └── InformationBlock.cs ├── MarkedNumericUpDown │ └── MarkedNumericUpDown.cs ├── MarkedTextBox │ └── MarkedTextBox.cs ├── ModalWindowHost │ └── ModalWindowHost.cs ├── NavigationView │ ├── NavigationView.cs │ └── NavigationViewItem.cs ├── OptionsDisplayItem │ └── OptionsDisplayItem.cs ├── PleasantBorder │ └── PleasantBorder.cs ├── PleasantMiniWindow │ └── PleasantMiniWindow.cs ├── PleasantModalWindow │ └── PleasantPopupElement.cs ├── PleasantTabView │ ├── PleasantTabItem.cs │ └── PleasantTabView.cs ├── PleasantView │ └── PleasantView.cs ├── PleasantWindow │ ├── PleasantWindow.cs │ └── PleasantWindowBase.cs ├── ProgressRing │ └── ProgressRing.cs ├── Ripple │ ├── Ripple.cs │ ├── RippleEffect.cs │ └── RippleHandler.cs ├── SmoothScrollViewer │ ├── SmoothScrollContentPresenter.cs │ └── SmoothScrollViewer.cs ├── Snackbar │ ├── PleasantSnackbar.cs │ ├── PleasantSnackbarOptions.cs │ └── SnackbarQueueManager.cs ├── ThemePreviewVariantScope │ └── ThemePreviewVariantScope.cs └── VirtualizingWrapPanel │ ├── Utils │ ├── RealizedWrappedElements.cs │ └── UVSize.cs │ └── VirtualizingWrapPanel.cs ├── Converters ├── BindingTranslateConverter.cs ├── ColorConverters.cs ├── ColorToTransparentConverter.cs ├── ColorToUIntConverter.cs ├── CornerRadiusFilterConverters.cs ├── FitSquarelyWithinAspectRatioConverter.cs ├── ForegroundBasedAccentConverter.cs ├── IntToColumnDefinitionWidthConverter.cs ├── MenuConverters.cs ├── OtherConverters.cs ├── ThicknessConverters.cs ├── TranslateConverter.cs └── TreeViewItemMarginConverters.cs ├── Core ├── Collections │ └── EventQueue.cs ├── Constants │ ├── PleasantDirectories.cs │ ├── PleasantFileNames.cs │ ├── PleasantThemes.cs │ └── ShadowDepths.cs ├── Extensions │ ├── LogicalExtensions.cs │ ├── Markup │ │ ├── ColorToTransparentExtension.cs │ │ ├── ForegroundBasedAccentExtension.cs │ │ ├── KeyGestureExtension.cs │ │ └── LocalizeExtension.cs │ ├── Media │ │ └── ColorExtensions.cs │ ├── MiscExtensions.cs │ ├── PropertyChangedExtensions.cs │ ├── ResourceDictionaryExtensions.cs │ ├── ResourceExtensions.cs │ ├── StringToNumberExtensions.cs │ ├── TabViewExtensions.cs │ └── WindowIconExtensions.cs ├── GenerationContexts │ └── PleasantSettingsGenerationContext.cs ├── Globalization.cs ├── Helpers │ ├── ApplicationHelper.cs │ └── ColorHelper.cs ├── Interfaces │ ├── IPleasantWindow.cs │ └── ISettingsProvider.cs ├── Localization │ ├── ILocalizer.cs │ ├── LocalizeObservable.cs │ ├── Localizer.cs │ └── RemoveLocalizeObserver.cs ├── Models │ ├── CustomTheme.cs │ └── Theme.cs ├── PleasantSettings.cs ├── PleasantThemesLoader.cs ├── Settings │ ├── AppPleasantUISettingsProvider.cs │ ├── RenderSettings.cs │ └── WindowSettings.cs ├── SettingsBase.cs ├── Structures │ └── MessageBoxButton.cs └── ViewModelBase.cs ├── PleasantTheme.axaml ├── PleasantTheme.axaml.cs ├── PleasantUI.csproj ├── Properties └── AssemblyInfo.cs ├── Reactive ├── AnonymousObserver.cs ├── CompositeDisposable.cs ├── Disposable.cs ├── Observable.cs └── Operators │ ├── CombineLatest.cs │ └── Sink.cs ├── Styling ├── BaseColorsPalette.axaml ├── ControlThemes │ ├── BasicControls │ │ ├── AdornerLayer.axaml │ │ ├── AutoCompleteBox.axaml │ │ ├── Button.axaml │ │ ├── ButtonSpinner.axaml │ │ ├── Calendar.axaml │ │ ├── CalendarButton.axaml │ │ ├── CalendarDatePicker.axaml │ │ ├── CalendarDayButton.axaml │ │ ├── CalendarItem.axaml │ │ ├── Carousel.axaml │ │ ├── CheckBox.axaml │ │ ├── ComboBox.axaml │ │ ├── ComboBoxItem.axaml │ │ ├── ContentControl.axaml │ │ ├── ContextMenu.axaml │ │ ├── DataValidationErrors.axaml │ │ ├── DatePicker.axaml │ │ ├── DateTimePickerShared.axaml │ │ ├── DropDownButton.axaml │ │ ├── EmbeddableControlRoot.axaml │ │ ├── Expander.axaml │ │ ├── FlyoutPresenter.axaml │ │ ├── GridSplitter.axaml │ │ ├── HeaderedContentControl.axaml │ │ ├── ItemsControl.axaml │ │ ├── Label.axaml │ │ ├── ListBox.axaml │ │ ├── ListBoxItem.axaml │ │ ├── Menu.axaml │ │ ├── MenuItem.axaml │ │ ├── NativeMenuBar.axaml │ │ ├── NotificationCard.axaml │ │ ├── NumericUpDown.axaml │ │ ├── OverlayPopupHost.axaml │ │ ├── PathIcon.axaml │ │ ├── PopupRoot.axaml │ │ ├── ProgressBar.axaml │ │ ├── RadioButton.axaml │ │ ├── RefreshContainer.axaml │ │ ├── RefreshVisualizer.axaml │ │ ├── RepeatButton.axaml │ │ ├── ScrollBar.axaml │ │ ├── ScrollViewer.axaml │ │ ├── SelectableTextBlock.axaml │ │ ├── Separator.axaml │ │ ├── Slider.axaml │ │ ├── SplitView.axaml │ │ ├── TabControl.axaml │ │ ├── TabItem.axaml │ │ ├── TabStrip.axaml │ │ ├── TabStripItem.axaml │ │ ├── TextBlock.axaml │ │ ├── TextBox.axaml │ │ ├── ThemeVariantScope.axaml │ │ ├── TimePicker.axaml │ │ ├── ToggleButton.axaml │ │ ├── ToggleSwitch.axaml │ │ ├── ToolTip.axaml │ │ ├── TransitioningContentControl.axaml │ │ ├── TreeView.axaml │ │ ├── TreeViewItem.axaml │ │ ├── Window.axaml │ │ └── WindowNotificationManager.axaml │ ├── Controls.axaml │ └── PleasantControls │ │ ├── ContentDialog.axaml │ │ ├── InformationBlock.axaml │ │ ├── MarkedNumericUpDown.axaml │ │ ├── MarkedTextBox.axaml │ │ ├── NavigationView.axaml │ │ ├── NavigationViewItem.axaml │ │ ├── OptionsDisplayItem.axaml │ │ ├── PleasantBorder.axaml │ │ ├── PleasantCaptionButtons.axaml │ │ ├── PleasantFlyoutPresenter.axaml │ │ ├── PleasantMiniWindow.axaml │ │ ├── PleasantSnackbar.axaml │ │ ├── PleasantTabItem.axaml │ │ ├── PleasantTabView.axaml │ │ ├── PleasantTitleBar.axaml │ │ ├── PleasantWindow.axaml │ │ ├── ProgressRing.axaml │ │ ├── RippleEffect.axaml │ │ └── SmoothScrollViewer.axaml ├── PleasantThemes.axaml └── UnifiedResources.axaml └── Transitions └── PleasantPageSlide.cs /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: onebeld # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 13 | custom: ['https://boosty.to/onebeld'] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021-2023 Dmitry Zhutkov (Onebeld) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /PleasantUIIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Onebeld/PleasantUI/08100a52e29a967b936735886644d81e08c1e757/PleasantUIIcon.png -------------------------------------------------------------------------------- /build/Package.props: -------------------------------------------------------------------------------- 1 |  2 | 3 | netstandard2.0 4 | enable 5 | enable 6 | default 7 | 5.0.0-alpha3 8 | Dmitry Zhutkov (Onebeld) 9 | Dmitry Zhutkov (Onebeld) 10 | theme, design, xaml, library, ui, gui, control, csharp, styled-components, interface, dotnet, nuget, style, avalonia, controls, user-interface, styles, avaloniaui, pleasant, graphical-user-interface 11 | UI library for Avalonia 12 | Onebeld 13 | 5.0.0 14 | 5.0.0 15 | true 16 | https://github.com/Onebeld/PleasantUI 17 | true 18 | Graphical user interface library for Avalonia with its own controls 19 | MIT 20 | README.md 21 | Public 22 | PleasantUIIcon.png 23 | true 24 | https://github.com/Onebeld/PleasantUI 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | True 35 | .\ 36 | PleasantUIIcon.png 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /designer/PleasantUI.Designer/App.axaml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /designer/PleasantUI.Designer/App.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Controls.ApplicationLifetimes; 3 | using Avalonia.Markup.Xaml; 4 | using PleasantUI.Controls; 5 | 6 | namespace PleasantUI.Designer; 7 | 8 | public partial class App : Application 9 | { 10 | public override void Initialize() => AvaloniaXamlLoader.Load(this); 11 | 12 | public override void OnFrameworkInitializationCompleted() 13 | { 14 | if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) 15 | desktop.MainWindow = new PleasantWindow(); 16 | 17 | base.OnFrameworkInitializationCompleted(); 18 | } 19 | } -------------------------------------------------------------------------------- /designer/PleasantUI.Designer/PleasantUI.Designer.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | WinExe 4 | net9.0 5 | enable 6 | true 7 | app.manifest 8 | true 9 | Full 10 | 11 | 12 | 13 | embedded 14 | true 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /designer/PleasantUI.Designer/Program.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using System; 3 | 4 | namespace PleasantUI.Designer; 5 | 6 | class Program 7 | { 8 | // Initialization code. Don't use any Avalonia, third-party APIs or any 9 | // SynchronizationContext-reliant code before AppMain is called: things aren't initialized 10 | // yet and stuff might break. 11 | [STAThread] 12 | public static void Main(string[] args) => BuildAvaloniaApp() 13 | .StartWithClassicDesktopLifetime(args); 14 | 15 | // Avalonia configuration, don't remove; also used by visual designer. 16 | public static AppBuilder BuildAvaloniaApp() 17 | => AppBuilder.Configure() 18 | .UsePlatformDetect() 19 | .LogToTrace(); 20 | } -------------------------------------------------------------------------------- /designer/PleasantUI.Designer/app.manifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 6 | 7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /generators/PleasantUI.MaterialIcons.SourceGenerator/MaterialIconsSourceGenerator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Net.Http; 4 | using System.Text; 5 | using Microsoft.CodeAnalysis; 6 | using System.Text.Json.Nodes; 7 | using System.Threading.Tasks; 8 | 9 | namespace PleasantUI.MaterialIcons.SourceGenerator; 10 | 11 | [Generator] 12 | public class MaterialIconsSourceGenerator : IIncrementalGenerator 13 | { 14 | const string MaterialIconsFetchApi = "https://dev.materialdesignicons.com/api/package/38EF63D0-4744-11E4-B3CF-842B2B6CFE1B"; 15 | 16 | private JsonNode? _json; 17 | 18 | public void Initialize(IncrementalGeneratorInitializationContext context) 19 | { 20 | HttpClient httpClient = new(); 21 | 22 | Task task = Task.Run(() => httpClient.GetStreamAsync(MaterialIconsFetchApi)); 23 | task.Wait(); 24 | 25 | Stream? dataStream = task.Result; 26 | JsonNode? json = JsonNode.Parse(dataStream); 27 | 28 | _json = json ?? throw new Exception("Unable to load JSON"); 29 | 30 | if (_json is null) 31 | throw new NullReferenceException("JSON is null"); 32 | 33 | JsonArray icons = _json.Root["icons"]!.AsArray(); 34 | 35 | const string generated = """ 36 | // 37 | using Avalonia.Media; 38 | 39 | namespace PleasantUI; 40 | 41 | public static partial class MaterialIcons 42 | { 43 | """; 44 | 45 | StringBuilder stringBuilder = new(generated); 46 | 47 | foreach (JsonNode? icon in icons) 48 | { 49 | string name = icon!["name"]!.GetValue().Underscore().Pascalize(); 50 | string data = icon["data"]!.GetValue(); 51 | 52 | stringBuilder.Append($"\tpublic static Geometry {name} = Geometry.Parse(\"{data}\");\n"); 53 | } 54 | 55 | stringBuilder.Append("}\n"); 56 | 57 | context.RegisterPostInitializationOutput(ctx => ctx.AddSource("MaterialIcons.g.cs", stringBuilder.ToString())); 58 | } 59 | } -------------------------------------------------------------------------------- /generators/PleasantUI.MaterialIcons.SourceGenerator/PleasantUI.MaterialIcons.SourceGenerator.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netstandard2.0 4 | false 5 | enable 6 | latest 7 | 8 | true 9 | true 10 | 11 | PleasantUI.MaterialIcons.SourceGenerator 12 | PleasantUI.MaterialIcons.SourceGenerator 13 | 14 | 15 | 16 | 17 | all 18 | runtime; build; native; contentfiles; analyzers; buildtransitive 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /generators/PleasantUI.MaterialIcons.SourceGenerator/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/launchsettings.json", 3 | "profiles": { 4 | "DebugRoslynSourceGenerator": { 5 | "commandName": "DebugRoslynComponent", 6 | "targetProject": "../../src/PleasantUI.MaterialIcons/PleasantUI.MaterialIcons.csproj" 7 | } 8 | } 9 | } -------------------------------------------------------------------------------- /generators/PleasantUI.MaterialIcons.SourceGenerator/StringExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Text.RegularExpressions; 2 | 3 | namespace PleasantUI.MaterialIcons.SourceGenerator; 4 | 5 | public static class StringExtensions 6 | { 7 | public static string Underscore(this string input) { 8 | return Regex.Replace( 9 | Regex.Replace( 10 | Regex.Replace(input, @"([\p{Lu}]+)([\p{Lu}][\p{Ll}])", "$1_$2"), @"([\p{Ll}\d])([\p{Lu}])", "$1_$2"), @"[-\s]", "_").ToLower(); 11 | } 12 | 13 | public static string Pascalize(this string input) 14 | { 15 | return Regex.Replace(input, "(?:^|_| +)(.)", match => match.Groups[1].Value.ToUpper()); 16 | } 17 | } -------------------------------------------------------------------------------- /global.json: -------------------------------------------------------------------------------- 1 | { 2 | "sdk": { 3 | "version": "8.0.0", 4 | "rollForward": "latestMajor", 5 | "allowPrerelease": true 6 | } 7 | } -------------------------------------------------------------------------------- /samples/PleasantUI.Example.Android/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /samples/PleasantUI.Example.Android/App.axaml: -------------------------------------------------------------------------------- 1 |  4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /samples/PleasantUI.Example.Android/App.axaml.cs: -------------------------------------------------------------------------------- 1 | namespace PleasantUI.Example.Android; 2 | 3 | public partial class App : PleasantUIExampleApp 4 | { 5 | 6 | public override void Initialize() => AvaloniaXamlLoader.Load(this); 7 | 8 | public override void OnFrameworkInitializationCompleted() 9 | { 10 | PleasantTheme = Styles[0] as PleasantTheme ?? throw new NullReferenceException("PleasantTheme is null"); 11 | 12 | if (ApplicationLifetime is ISingleViewApplicationLifetime lifetime) 13 | { 14 | lifetime.MainView = new PleasantMainView 15 | { 16 | DataContext = ViewModel 17 | }; 18 | } 19 | 20 | base.OnFrameworkInitializationCompleted(); 21 | } 22 | } -------------------------------------------------------------------------------- /samples/PleasantUI.Example.Android/Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Onebeld/PleasantUI/08100a52e29a967b936735886644d81e08c1e757/samples/PleasantUI.Example.Android/Icon.png -------------------------------------------------------------------------------- /samples/PleasantUI.Example.Android/MainActivity.cs: -------------------------------------------------------------------------------- 1 | using PleasantUI.Core; 2 | 3 | namespace PleasantUI.Example.Android; 4 | 5 | [Activity( 6 | Label = "PleasantUI.Example", 7 | Theme = "@style/MyTheme.NoActionBar", 8 | Icon = "@drawable/icon", 9 | MainLauncher = true, 10 | ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize | ConfigChanges.UiMode)] 11 | public class MainActivity : AvaloniaMainActivity 12 | { 13 | protected override AppBuilder CustomizeAppBuilder(AppBuilder builder) 14 | { 15 | return base.CustomizeAppBuilder(builder); 16 | } 17 | 18 | protected override void OnStop() 19 | { 20 | PleasantSettings.Save(); 21 | 22 | base.OnStop(); 23 | } 24 | } -------------------------------------------------------------------------------- /samples/PleasantUI.Example.Android/PleasantMainView.axaml: -------------------------------------------------------------------------------- 1 |  8 | 9 | 10 | -------------------------------------------------------------------------------- /samples/PleasantUI.Example.Android/PleasantMainView.axaml.cs: -------------------------------------------------------------------------------- 1 | using PleasantUI.Controls; 2 | using PleasantUI.Core; 3 | 4 | namespace PleasantUI.Example.Android; 5 | 6 | public partial class PleasantMainView : PleasantView 7 | { 8 | public PleasantMainView() 9 | { 10 | InitializeComponent(); 11 | } 12 | 13 | private void OnUnloaded(object? sender, RoutedEventArgs e) 14 | { 15 | PleasantSettings.Save(); 16 | } 17 | 18 | protected override void OnApplyTemplate(TemplateAppliedEventArgs e) 19 | { 20 | base.OnApplyTemplate(e); 21 | 22 | /*App.ViewModel.NotificationManager = new PleasantNotificationManager(this) 23 | { 24 | Position = NotificationPosition.TopRight, 25 | MaxItems = 3, 26 | ZIndex = 1 27 | };*/ 28 | } 29 | } -------------------------------------------------------------------------------- /samples/PleasantUI.Example.Android/PleasantUI.Example.Android.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Exe 4 | net8.0-android 5 | 26 6 | enable 7 | com.Onebeld.PleasantUI.Example 8 | 1 9 | 1.0 10 | apk 11 | true 12 | 13 | 14 | 16 | 17 | 18 | 19 | true 20 | true 21 | 22 | 23 | 24 | 25 | Resources\drawable\Icon.png 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /samples/PleasantUI.Example.Android/Properties/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /samples/PleasantUI.Example.Android/Resources/AboutResources.txt: -------------------------------------------------------------------------------- 1 | Images, layout descriptions, binary blobs and string dictionaries can be included 2 | in your application as resource files. Various Android APIs are designed to 3 | operate on the resource IDs instead of dealing with images, strings or binary blobs 4 | directly. 5 | 6 | For example, a sample Android app that contains a user interface layout (main.axml), 7 | an internationalization string table (strings.xml) and some icons (drawable-XXX/icon.png) 8 | would keep its resources in the "Resources" directory of the application: 9 | 10 | Resources/ 11 | drawable/ 12 | icon.png 13 | 14 | layout/ 15 | main.axml 16 | 17 | values/ 18 | strings.xml 19 | 20 | In order to get the build system to recognize Android resources, set the build action to 21 | "AndroidResource". The native Android APIs do not operate directly with filenames, but 22 | instead operate on resource IDs. When you compile an Android application that uses resources, 23 | the build system will package the resources for distribution and generate a class called "R" 24 | (this is an Android convention) that contains the tokens for each one of the resources 25 | included. For example, for the above Resources layout, this is what the R class would expose: 26 | 27 | public class R { 28 | public class drawable { 29 | public const int icon = 0x123; 30 | } 31 | 32 | public class layout { 33 | public const int main = 0x456; 34 | } 35 | 36 | public class strings { 37 | public const int first_string = 0xabc; 38 | public const int second_string = 0xbcd; 39 | } 40 | } 41 | 42 | You would then use R.drawable.icon to reference the drawable/icon.png file, or R.layout.main 43 | to reference the layout/main.axml file, or R.strings.first_string to reference the first 44 | string in the dictionary file values/strings.xml. -------------------------------------------------------------------------------- /samples/PleasantUI.Example.Android/Resources/drawable/splash_screen.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /samples/PleasantUI.Example.Android/Resources/values-night/colors.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | #212121 4 | 5 | -------------------------------------------------------------------------------- /samples/PleasantUI.Example.Android/Resources/values-v31/styles.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 5 | 6 | 16 | 20 | 21 | -------------------------------------------------------------------------------- /samples/PleasantUI.Example.Android/Resources/values/colors.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | #FFFFFF 4 | 5 | -------------------------------------------------------------------------------- /samples/PleasantUI.Example.Android/Resources/values/styles.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /samples/PleasantUI.Example.Browser/App.axaml: -------------------------------------------------------------------------------- 1 |  4 | 5 | 6 | 7 | 8 | #E4000000 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /samples/PleasantUI.Example.Browser/App.axaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Avalonia.Controls.ApplicationLifetimes; 3 | using Avalonia.Markup.Xaml; 4 | 5 | namespace PleasantUI.Example.Browser; 6 | 7 | public partial class App : PleasantUiExampleApp 8 | { 9 | public override void Initialize() => AvaloniaXamlLoader.Load(this); 10 | 11 | public override void OnFrameworkInitializationCompleted() 12 | { 13 | PleasantTheme = Styles[0] as PleasantTheme ?? throw new NullReferenceException("PleasantTheme is null"); 14 | 15 | if (ApplicationLifetime is ISingleViewApplicationLifetime lifetime) 16 | { 17 | lifetime.MainView = new PleasantMainView 18 | { 19 | DataContext = ViewModel 20 | }; 21 | } 22 | 23 | base.OnFrameworkInitializationCompleted(); 24 | } 25 | } -------------------------------------------------------------------------------- /samples/PleasantUI.Example.Browser/PleasantMainView.axaml: -------------------------------------------------------------------------------- 1 |  8 | 9 | 10 | -------------------------------------------------------------------------------- /samples/PleasantUI.Example.Browser/PleasantMainView.axaml.cs: -------------------------------------------------------------------------------- 1 | using PleasantUI.Controls; 2 | 3 | namespace PleasantUI.Example.Browser; 4 | 5 | public partial class PleasantMainView : PleasantView 6 | { 7 | public PleasantMainView() 8 | { 9 | InitializeComponent(); 10 | } 11 | } -------------------------------------------------------------------------------- /samples/PleasantUI.Example.Browser/PleasantUI.Example.Browser.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | net9.0-browser 4 | Exe 5 | true 6 | enable 7 | 5 8 | false 9 | true 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /samples/PleasantUI.Example.Browser/Program.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.Threading.Tasks; 3 | using Avalonia; 4 | using Avalonia.Browser; 5 | using PleasantUI.Example.Browser; 6 | 7 | internal sealed partial class Program 8 | { 9 | private static Task Main(string[] args) 10 | { 11 | Trace.Listeners.Add(new ConsoleTraceListener()); 12 | 13 | return BuildAvaloniaApp() 14 | .LogToTrace() 15 | .StartBrowserAppAsync("out"); 16 | } 17 | 18 | public static AppBuilder BuildAvaloniaApp() 19 | => AppBuilder.Configure(); 20 | } -------------------------------------------------------------------------------- /samples/PleasantUI.Example.Browser/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | [assembly:System.Runtime.Versioning.SupportedOSPlatform("browser")] 2 | -------------------------------------------------------------------------------- /samples/PleasantUI.Example.Browser/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "PleasantUI.Example.Browser": { 4 | "commandName": "Project", 5 | "launchBrowser": true, 6 | "environmentVariables": { 7 | "ASPNETCORE_ENVIRONMENT": "Development" 8 | }, 9 | "applicationUrl": "https://localhost:7169;http://localhost:5235", 10 | "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /samples/PleasantUI.Example.Browser/runtimeconfig.template.json: -------------------------------------------------------------------------------- 1 | { 2 | "wasmHostProperties": { 3 | "perHostConfig": [ 4 | { 5 | "name": "browser", 6 | "host": "browser" 7 | } 8 | ] 9 | } 10 | } -------------------------------------------------------------------------------- /samples/PleasantUI.Example.Browser/wwwroot/app.css: -------------------------------------------------------------------------------- 1 | /* HTML styles for the splash screen */ 2 | .avalonia-splash { 3 | position: absolute; 4 | height: 100%; 5 | width: 100%; 6 | background: white; 7 | font-family: 'Outfit', sans-serif; 8 | justify-content: center; 9 | align-items: center; 10 | display: flex; 11 | pointer-events: none; 12 | } 13 | 14 | /* Light theme styles */ 15 | @media (prefers-color-scheme: light) { 16 | .avalonia-splash { 17 | background: white; 18 | } 19 | 20 | .avalonia-splash h2 { 21 | color: #1b2a4e; 22 | } 23 | 24 | .avalonia-splash a { 25 | color: #0D6EFD; 26 | } 27 | } 28 | 29 | @media (prefers-color-scheme: dark) { 30 | .avalonia-splash { 31 | background: #1b2a4e; 32 | } 33 | 34 | .avalonia-splash h2 { 35 | color: white; 36 | } 37 | 38 | .avalonia-splash a { 39 | color: white; 40 | } 41 | } 42 | 43 | .avalonia-splash h2 { 44 | font-weight: 400; 45 | font-size: 1.5rem; 46 | } 47 | 48 | .avalonia-splash a { 49 | text-decoration: none; 50 | font-size: 2.5rem; 51 | display: block; 52 | } 53 | 54 | .avalonia-splash.splash-close { 55 | transition: opacity 200ms, display 200ms; 56 | display: none; 57 | opacity: 0; 58 | } 59 | -------------------------------------------------------------------------------- /samples/PleasantUI.Example.Browser/wwwroot/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Onebeld/PleasantUI/08100a52e29a967b936735886644d81e08c1e757/samples/PleasantUI.Example.Browser/wwwroot/favicon.ico -------------------------------------------------------------------------------- /samples/PleasantUI.Example.Browser/wwwroot/main.js: -------------------------------------------------------------------------------- 1 | import { dotnet } from './_framework/dotnet.js' 2 | 3 | const is_browser = typeof window != "undefined"; 4 | if (!is_browser) throw new Error(`Expected to be running in a browser`); 5 | 6 | const dotnetRuntime = await dotnet 7 | .withDiagnosticTracing(false) 8 | .withApplicationArgumentsFromQuery() 9 | .create(); 10 | 11 | const config = dotnetRuntime.getConfig(); 12 | 13 | await dotnetRuntime.runMain(config.mainAssemblyName, [globalThis.location.href]); 14 | -------------------------------------------------------------------------------- /samples/PleasantUI.Example.Desktop/App.axaml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | #E4000000 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /samples/PleasantUI.Example.Desktop/App.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using Avalonia.Controls.ApplicationLifetimes; 3 | using Avalonia.Markup.Xaml; 4 | using PleasantUI.Controls; 5 | 6 | namespace PleasantUI.Example.Desktop; 7 | 8 | public partial class App : PleasantUiExampleApp 9 | { 10 | public override void Initialize() => AvaloniaXamlLoader.Load(this); 11 | 12 | public override void OnFrameworkInitializationCompleted() 13 | { 14 | if (ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop) 15 | return; 16 | 17 | if (Design.IsDesignMode) 18 | { 19 | desktop.MainWindow = new PleasantWindow(); 20 | 21 | base.OnFrameworkInitializationCompleted(); 22 | return; 23 | } 24 | 25 | PleasantTheme = Styles[0] as PleasantTheme ?? throw new NullReferenceException("PleasantTheme is null"); 26 | 27 | Main = new MainWindow 28 | { 29 | DataContext = ViewModel 30 | }; 31 | 32 | TopLevel = TopLevel.GetTopLevel(Main as PleasantWindow) ?? throw new NullReferenceException("TopLevel is null"); 33 | 34 | desktop.MainWindow = Main as PleasantWindow; 35 | 36 | base.OnFrameworkInitializationCompleted(); 37 | } 38 | } -------------------------------------------------------------------------------- /samples/PleasantUI.Example.Desktop/MainWindow.axaml: -------------------------------------------------------------------------------- 1 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /samples/PleasantUI.Example.Desktop/MainWindow.axaml.cs: -------------------------------------------------------------------------------- 1 | using PleasantUI.Controls; 2 | 3 | namespace PleasantUI.Example.Desktop; 4 | 5 | public partial class MainWindow : PleasantWindow 6 | { 7 | public MainWindow() => InitializeComponent(); 8 | } -------------------------------------------------------------------------------- /samples/PleasantUI.Example.Desktop/PleasantUI.Example.Desktop.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Exe 4 | net9.0 5 | enable 6 | enable 7 | true 8 | app.manifest 9 | true 10 | true 11 | Dmitry Zhutkov (Onebeld) 12 | PleasantUIIcon.ico 13 | true 14 | 15 | 16 | 17 | embedded 18 | true 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /samples/PleasantUI.Example.Desktop/PleasantUIIcon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Onebeld/PleasantUI/08100a52e29a967b936735886644d81e08c1e757/samples/PleasantUI.Example.Desktop/PleasantUIIcon.ico -------------------------------------------------------------------------------- /samples/PleasantUI.Example.Desktop/Program.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | using Avalonia; 3 | using PleasantUI.Example.Logging.Logging; 4 | using Serilog; 5 | 6 | namespace PleasantUI.Example.Desktop; 7 | 8 | class Program 9 | { 10 | private static readonly string PathToLog = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Logs"); 11 | private static readonly string FileName = Path.Combine(PathToLog, 12 | $"{AppDomain.CurrentDomain.FriendlyName}_{DateTime.Now:dd.MM.yyyy}.log"); 13 | 14 | [STAThread] 15 | public static void Main(string[] args) 16 | { 17 | if (!Directory.Exists(PathToLog)) 18 | Directory.CreateDirectory(PathToLog); 19 | 20 | bool createLogFile = !File.Exists(FileName); 21 | 22 | using PleasantLogger logger = new( 23 | new LoggerConfiguration().WriteTo.File(FileName, outputTemplate: "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz}] [{Level}] | {Message:lj}{NewLine}{Exception}") 24 | ); 25 | 26 | if (createLogFile) 27 | WriteDeviceInformation(); 28 | 29 | BuildAvaloniaApp() 30 | .StartWithClassicDesktopLifetime(args); 31 | } 32 | 33 | private static void WriteDeviceInformation() 34 | { 35 | StringBuilder stringBuilder = new(); 36 | 37 | stringBuilder.AppendLine($"OS: {Environment.OSVersion}"); 38 | stringBuilder.AppendLine($"CPU: {Environment.ProcessorCount} cores"); 39 | 40 | Log.Information("Device information:\n" + stringBuilder); 41 | } 42 | 43 | public static AppBuilder BuildAvaloniaApp() 44 | { 45 | AppBuilder appBuilder = AppBuilder.Configure(); 46 | appBuilder.UsePlatformDetect(); 47 | 48 | appBuilder 49 | .With(new Win32PlatformOptions 50 | { 51 | OverlayPopups = false 52 | }) 53 | .With(new MacOSPlatformOptions 54 | { 55 | DisableDefaultApplicationMenuItems = true, 56 | ShowInDock = false, 57 | DisableNativeMenus = true 58 | }) 59 | .With(new X11PlatformOptions 60 | { 61 | OverlayPopups = true 62 | }); 63 | 64 | appBuilder.LogToSerilog(); 65 | 66 | return appBuilder; 67 | } 68 | } -------------------------------------------------------------------------------- /samples/PleasantUI.Example.Desktop/app.manifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 6 | 7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /samples/PleasantUI.Example/DataTemplates/ControlPageCardItemTemplate.axaml: -------------------------------------------------------------------------------- 1 |  4 | 5 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /samples/PleasantUI.Example/Interfaces/IPage.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | 3 | namespace PleasantUI.Example.Interfaces; 4 | 5 | public interface IPage 6 | { 7 | string Title { get; } 8 | 9 | bool ShowTitle { get; } 10 | 11 | Control Content { get; } 12 | } -------------------------------------------------------------------------------- /samples/PleasantUI.Example/Logging/Logging/LoggerExtensions.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Logging; 3 | 4 | namespace PleasantUI.Example.Logging.Logging; 5 | 6 | /// 7 | /// Extensions for to log to Serilog. 8 | /// 9 | public static class LoggerExtensions 10 | { 11 | /// 12 | /// Logs to Serilog with the given log level and areas. 13 | /// 14 | /// The . 15 | /// The level of the log messages to be written to Serilog. 16 | /// The areas to log. 17 | /// The same instance of the . 18 | public static AppBuilder LogToSerilog(this AppBuilder builder, LogEventLevel level = LogEventLevel.Warning, 19 | params string[] areas) 20 | { 21 | Avalonia.Logging.Logger.Sink = new SerilogSink(level, areas); 22 | return builder; 23 | } 24 | } -------------------------------------------------------------------------------- /samples/PleasantUI.Example/Logging/Logging/PleasantLogger.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.Runtime.ExceptionServices; 3 | using Serilog; 4 | 5 | namespace PleasantUI.Example.Logging.Logging; 6 | 7 | /// 8 | /// A logger that handles unhandled exceptions and first chance exceptions. 9 | /// 10 | public class PleasantLogger : IDisposable 11 | { 12 | /// 13 | /// Initializes a new instance of the class. 14 | /// 15 | /// The logger configuration. 16 | public PleasantLogger(LoggerConfiguration loggerConfiguration) 17 | { 18 | Log.Logger = loggerConfiguration.CreateLogger(); 19 | 20 | AppDomain.CurrentDomain.FirstChanceException += CurrentDomainOnFirstChanceException; 21 | AppDomain.CurrentDomain.UnhandledException += CurrentDomainOnUnhandledException; 22 | 23 | Log.Information("The logger has been initialized"); 24 | } 25 | 26 | /// 27 | public void Dispose() 28 | { 29 | Log.Information("The logger has been disposed"); 30 | 31 | AppDomain.CurrentDomain.FirstChanceException -= CurrentDomainOnFirstChanceException; 32 | AppDomain.CurrentDomain.UnhandledException -= CurrentDomainOnUnhandledException; 33 | 34 | Log.CloseAndFlush(); 35 | } 36 | 37 | private static void CurrentDomainOnFirstChanceException(object? sender, FirstChanceExceptionEventArgs e) 38 | { 39 | StackTrace stackTrace = new(1, true); 40 | Log.Error($"An handled exception occurred\n{e.Exception.GetType()}: {e.Exception.Message}\n{stackTrace}"); 41 | } 42 | 43 | private static void CurrentDomainOnUnhandledException(object sender, UnhandledExceptionEventArgs e) 44 | { 45 | if (e.ExceptionObject is Exception ex) 46 | Log.Fatal(ex, "An unhandled exception occurred"); 47 | 48 | Log.CloseAndFlush(); 49 | } 50 | } -------------------------------------------------------------------------------- /samples/PleasantUI.Example/MainView.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using PleasantUI.Example.Views; 3 | 4 | namespace PleasantUI.Example; 5 | 6 | public partial class MainView : UserControl 7 | { 8 | public MainView() 9 | { 10 | InitializeComponent(); 11 | 12 | HomeView.FuncControl += () => new HomeView { DataContext = DataContext }; 13 | SettingsView.FuncControl += () => new SettingsView(); 14 | AboutView.FuncControl += () => new AboutView(); 15 | } 16 | } -------------------------------------------------------------------------------- /samples/PleasantUI.Example/Models/ControlPageCard.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Media; 2 | using CommunityToolkit.Mvvm.Input; 3 | using CommunityToolkit.Mvvm.Messaging; 4 | using CommunityToolkit.Mvvm.Messaging.Messages; 5 | using PleasantUI.Example.Interfaces; 6 | 7 | namespace PleasantUI.Example.Models; 8 | 9 | public partial class ControlPageCard 10 | { 11 | public string Title { get; set; } 12 | 13 | public Geometry Icon { get; set; } 14 | 15 | public string Description { get; set; } 16 | 17 | public IPage Page { get; set; } 18 | 19 | public ControlPageCard(string title, Geometry icon, string description, IPage page) 20 | { 21 | Title = title; 22 | Icon = icon; 23 | Description = description; 24 | Page = page; 25 | } 26 | 27 | [RelayCommand] 28 | public void OpenPage() 29 | { 30 | WeakReferenceMessenger.Default.Send(new ValueChangedMessage(Page)); 31 | } 32 | } -------------------------------------------------------------------------------- /samples/PleasantUI.Example/Models/DataModel.cs: -------------------------------------------------------------------------------- 1 | namespace PleasantUI.Example.Models; 2 | 3 | public class DataModel 4 | { 5 | public string Name { get; set; } 6 | 7 | public int Age { get; set; } 8 | 9 | public bool IsNew { get; set; } 10 | 11 | public DataModel(string name, int age, bool isNew) 12 | { 13 | Name = name; 14 | Age = age; 15 | IsNew = isNew; 16 | } 17 | } -------------------------------------------------------------------------------- /samples/PleasantUI.Example/Pages/BasicControls/ButtonPage.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using PleasantUI.Example.Interfaces; 3 | using PleasantUI.Example.Views.Pages.ControlPages; 4 | 5 | namespace PleasantUI.Example.Pages.BasicControls; 6 | 7 | public class ButtonPage : IPage 8 | { 9 | public string Title { get; } = "Button"; 10 | 11 | public bool ShowTitle { get; } = true; 12 | 13 | public Control Content 14 | { 15 | get { return new ButtonPageView(); } 16 | } 17 | } -------------------------------------------------------------------------------- /samples/PleasantUI.Example/Pages/BasicControls/CalendarPage.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using PleasantUI.Example.Interfaces; 3 | 4 | namespace PleasantUI.Example.Pages.BasicControls; 5 | 6 | public class CalendarPage : IPage 7 | { 8 | public string Title { get; } = "Calendar"; 9 | public bool ShowTitle { get; } = true; 10 | public Control Content { get; } = null!; 11 | } -------------------------------------------------------------------------------- /samples/PleasantUI.Example/Pages/BasicControls/CarouselPage.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using PleasantUI.Example.Interfaces; 3 | 4 | namespace PleasantUI.Example.Pages.BasicControls; 5 | 6 | public class CarouselPage : IPage 7 | { 8 | public string Title { get; } = "Carousel"; 9 | public bool ShowTitle { get; } = true; 10 | public Control Content { get; } = null!; 11 | } -------------------------------------------------------------------------------- /samples/PleasantUI.Example/Pages/BasicControls/CheckBoxPage.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using PleasantUI.Example.Interfaces; 3 | using PleasantUI.Example.Views.Pages.ControlPages; 4 | 5 | namespace PleasantUI.Example.Pages.BasicControls; 6 | 7 | public class CheckBoxPage : IPage 8 | { 9 | public string Title { get; } = "CheckBox"; 10 | 11 | public bool ShowTitle { get; } = true; 12 | 13 | public Control Content 14 | { 15 | get { return new CheckBoxPageView(); } 16 | } 17 | } -------------------------------------------------------------------------------- /samples/PleasantUI.Example/Pages/BasicControls/ComboBoxPage.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using PleasantUI.Example.Interfaces; 3 | 4 | namespace PleasantUI.Example.Pages.BasicControls; 5 | 6 | public class ComboBoxPage : IPage 7 | { 8 | public string Title { get; } = "ComboBox"; 9 | public bool ShowTitle { get; } = true; 10 | public Control Content { get; } = null!; 11 | } -------------------------------------------------------------------------------- /samples/PleasantUI.Example/Pages/BasicControls/DataGridPage.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using PleasantUI.Example.Interfaces; 3 | using PleasantUI.Example.Views.Pages.ControlPages; 4 | 5 | namespace PleasantUI.Example.Pages.BasicControls; 6 | 7 | public class DataGridPage : IPage 8 | { 9 | public string Title { get; } = "DataGrid"; 10 | public bool ShowTitle { get; } = true; 11 | 12 | public Control Content => new DataGridPageView(); 13 | } -------------------------------------------------------------------------------- /samples/PleasantUI.Example/Pages/BasicControls/HomePage.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using PleasantUI.Example.Interfaces; 3 | using PleasantUI.Example.Views.Pages; 4 | 5 | namespace PleasantUI.Example.Pages.BasicControls; 6 | 7 | public class HomePage : IPage 8 | { 9 | public string Title { get; } = "Home"; 10 | 11 | public bool ShowTitle { get; } = false; 12 | 13 | public Control Content 14 | { 15 | get { return new HomePageView(); } 16 | } 17 | } -------------------------------------------------------------------------------- /samples/PleasantUI.Example/Pages/BasicControls/ProgressBarPage.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using PleasantUI.Example.Interfaces; 3 | 4 | namespace PleasantUI.Example.Pages.BasicControls; 5 | 6 | public class ProgressBarPage : IPage 7 | { 8 | public string Title { get; } = "ProgressBar"; 9 | public bool ShowTitle { get; } = true; 10 | public Control Content { get; } = null!; 11 | } -------------------------------------------------------------------------------- /samples/PleasantUI.Example/Pages/BasicControls/SliderPage.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using PleasantUI.Example.Interfaces; 3 | 4 | namespace PleasantUI.Example.Pages.BasicControls; 5 | 6 | public class SliderPage : IPage 7 | { 8 | public string Title { get; } = "Slider"; 9 | public bool ShowTitle { get; } = true; 10 | public Control Content { get; } = null!; 11 | } -------------------------------------------------------------------------------- /samples/PleasantUI.Example/Pages/BasicControls/TextBoxPage.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using PleasantUI.Example.Interfaces; 3 | 4 | namespace PleasantUI.Example.Pages.BasicControls; 5 | 6 | public class TextBoxPage : IPage 7 | { 8 | public string Title { get; } = "TextBox"; 9 | public bool ShowTitle { get; } = true; 10 | public Control Content { get; } = null!; 11 | } -------------------------------------------------------------------------------- /samples/PleasantUI.Example/Pages/PleasantControls/InformationBlockPage.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using PleasantUI.Example.Interfaces; 3 | 4 | namespace PleasantUI.Example.Pages.PleasantControls; 5 | 6 | public class InformationBlockPage : IPage 7 | { 8 | public string Title { get; } = "InformationBlock"; 9 | public bool ShowTitle { get; } = true; 10 | public Control Content { get; } = null!; 11 | } -------------------------------------------------------------------------------- /samples/PleasantUI.Example/Pages/PleasantControls/OptionsDisplayItemPage.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using PleasantUI.Example.Interfaces; 3 | 4 | namespace PleasantUI.Example.Pages.PleasantControls; 5 | 6 | public class OptionsDisplayItemPage : IPage 7 | { 8 | public string Title { get; } = "OptionsDisplayItem"; 9 | public bool ShowTitle { get; } = true; 10 | public Control Content { get; } = null!; 11 | } -------------------------------------------------------------------------------- /samples/PleasantUI.Example/Pages/PleasantControls/PleasantSnackbarPage.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using PleasantUI.Example.Interfaces; 3 | using PleasantUI.Example.Views.Pages.PleasantControlPages; 4 | 5 | namespace PleasantUI.Example.Pages.PleasantControls; 6 | 7 | public class PleasantSnackbarPage : IPage 8 | { 9 | public string Title { get; } = "PleasantSnackbar"; 10 | public bool ShowTitle { get; } = true; 11 | 12 | public Control Content 13 | { 14 | get 15 | { 16 | return new PleasantSnackbarPageView(); 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /samples/PleasantUI.Example/Pages/PleasantControls/PleasantTabViewPage.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using PleasantUI.Example.Interfaces; 3 | 4 | namespace PleasantUI.Example.Pages.PleasantControls; 5 | 6 | public class PleasantTabViewPage : IPage 7 | { 8 | public string Title { get; } = "PleasantTabView"; 9 | public bool ShowTitle { get; } = true; 10 | public Control Content { get; } = null!; 11 | } -------------------------------------------------------------------------------- /samples/PleasantUI.Example/Pages/PleasantControls/ProgressPage.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using PleasantUI.Example.Interfaces; 3 | using PleasantUI.Example.Views.Pages.PleasantControlPages; 4 | 5 | namespace PleasantUI.Example.Pages.PleasantControls; 6 | 7 | public class ProgressPage : IPage 8 | { 9 | public string Title { get; } = "Progress"; 10 | public bool ShowTitle { get; } = true; 11 | public Control Content 12 | { 13 | get => new ProgressRingPageView(); 14 | } 15 | } -------------------------------------------------------------------------------- /samples/PleasantUI.Example/Pages/ToolKit/MessageBoxPage.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using PleasantUI.Example.Interfaces; 3 | using PleasantUI.Example.Views.Pages.ToolkitPages; 4 | 5 | namespace PleasantUI.Example.Pages.Toolkit; 6 | 7 | public class MessageBoxPage : IPage 8 | { 9 | public string Title { get; } = "MessageBox"; 10 | public bool ShowTitle { get; } = true; 11 | 12 | public Control Content => new MessageBoxPageView(); 13 | } -------------------------------------------------------------------------------- /samples/PleasantUI.Example/PleasantUIExampleApp.cs: -------------------------------------------------------------------------------- 1 | using System.Resources; 2 | using Avalonia; 3 | using Avalonia.Controls; 4 | using PleasantUI.Core.Interfaces; 5 | using PleasantUI.Core.Localization; 6 | using PleasantUI.Example.Structures; 7 | using PleasantUI.Example.ViewModels; 8 | 9 | namespace PleasantUI.Example; 10 | 11 | public class PleasantUiExampleApp : Application 12 | { 13 | public static PleasantTheme PleasantTheme { get; protected set; } = null!; 14 | 15 | public static IPleasantWindow Main { get; protected set; } = null!; 16 | 17 | public static AppViewModel ViewModel { get; } = null!; 18 | 19 | public static TopLevel? TopLevel { get; protected set; } 20 | 21 | static PleasantUiExampleApp() 22 | { 23 | if (!Design.IsDesignMode) 24 | ViewModel = new AppViewModel(); 25 | } 26 | 27 | public PleasantUiExampleApp() 28 | { 29 | if (!Design.IsDesignMode) 30 | DataContext = ViewModel; 31 | 32 | Localizer.AddRes(new ResourceManager(typeof(Properties.Localizations.App))); 33 | Localizer.AddRes(new ResourceManager(typeof(Properties.Localizations.Library))); 34 | 35 | Localizer.ChangeLang("en"); 36 | } 37 | 38 | public static string LanguageKey { get; set; } = "en"; 39 | 40 | public static readonly Language[] Languages = 41 | [ 42 | new("English (English)", "en"), 43 | new("Русский (Russian)", "ru") 44 | ]; 45 | } -------------------------------------------------------------------------------- /samples/PleasantUI.Example/Structures/Language.cs: -------------------------------------------------------------------------------- 1 | namespace PleasantUI.Example.Structures; 2 | 3 | public readonly struct Language(string name, string key) 4 | { 5 | public string Name { get; } = name; 6 | 7 | public string Key { get; } = key; 8 | } -------------------------------------------------------------------------------- /samples/PleasantUI.Example/ViewModels/Pages/ControlPages/DataGridViewModel.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Collections; 2 | using CommunityToolkit.Mvvm.ComponentModel; 3 | using PleasantUI.Example.Models; 4 | 5 | namespace PleasantUI.Example.ViewModels.Pages.ControlPages; 6 | 7 | public class DataGridViewModel : ObservableObject 8 | { 9 | public AvaloniaList DataModels { get; } 10 | 11 | public DataGridViewModel() 12 | { 13 | DataModels = new AvaloniaList 14 | { 15 | new("John", 23, true), 16 | new("Jane", 24, false), 17 | new("Jack", 25, true), 18 | new("Jill", 26, false), 19 | new("Joe", 27, true), 20 | }; 21 | } 22 | } -------------------------------------------------------------------------------- /samples/PleasantUI.Example/ViewModels/Pages/ControlPages/ProgressRingViewModel.cs: -------------------------------------------------------------------------------- 1 | using CommunityToolkit.Mvvm.ComponentModel; 2 | 3 | namespace PleasantUI.Example.ViewModels.Pages.ControlPages; 4 | 5 | public partial class ProgressRingViewModel : ObservableObject 6 | { 7 | [ObservableProperty] 8 | private double _value = 25; 9 | 10 | [ObservableProperty] 11 | private bool _isIndeterminate; 12 | } -------------------------------------------------------------------------------- /samples/PleasantUI.Example/ViewModels/Pages/SettingsViewModel.cs: -------------------------------------------------------------------------------- 1 | using CommunityToolkit.Mvvm.ComponentModel; 2 | using CommunityToolkit.Mvvm.Input; 3 | using PleasantUI.Core; 4 | using PleasantUI.Core.Localization; 5 | using PleasantUI.Core.Models; 6 | using PleasantUI.Example.Structures; 7 | using PleasantUI.ToolKit; 8 | 9 | namespace PleasantUI.Example.ViewModels.Pages; 10 | 11 | public partial class SettingsViewModel : ObservableObject 12 | { 13 | public Language SelectedLanguage 14 | { 15 | get => PleasantUiExampleApp.Languages.First(language => language.Key == PleasantUiExampleApp.LanguageKey); 16 | set 17 | { 18 | PleasantUiExampleApp.LanguageKey = value.Key; 19 | Localizer.ChangeLang(value.Key); 20 | } 21 | } 22 | 23 | public Theme? SelectedTheme 24 | { 25 | get => PleasantSettings.Current?.Theme is string themeName 26 | ? PleasantTheme.Themes.FirstOrDefault(theme => theme.Name == themeName) 27 | : null; 28 | 29 | set 30 | { 31 | if (PleasantSettings.Current is not null) 32 | PleasantSettings.Current.Theme = value?.Name ?? "System"; 33 | } 34 | } 35 | 36 | public CustomTheme? SelectedCustomTheme 37 | { 38 | get => PleasantTheme.SelectedCustomTheme; 39 | set => PleasantTheme.SelectedCustomTheme = value; 40 | } 41 | 42 | [RelayCommand] 43 | private async Task CreateThemeAsync() 44 | { 45 | CustomTheme? newCustomTheme = await ThemeEditorWindow.EditTheme(PleasantUiExampleApp.Main, null); 46 | 47 | if (newCustomTheme is null) 48 | return; 49 | 50 | PleasantTheme.CustomThemes.Add(newCustomTheme); 51 | } 52 | 53 | [RelayCommand] 54 | private async Task EditThemeAsync(CustomTheme customTheme) 55 | { 56 | CustomTheme? newCustomTheme = await ThemeEditorWindow.EditTheme(PleasantUiExampleApp.Main, customTheme); 57 | 58 | if (newCustomTheme is null) 59 | return; 60 | 61 | PleasantUiExampleApp.PleasantTheme.EditCustomTheme(customTheme, newCustomTheme); 62 | } 63 | 64 | [RelayCommand] 65 | private void DeleteTheme(CustomTheme customTheme) 66 | { 67 | PleasantTheme.CustomThemes.Remove(customTheme); 68 | } 69 | } -------------------------------------------------------------------------------- /samples/PleasantUI.Example/Views/AboutView.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | 3 | namespace PleasantUI.Example.Views; 4 | 5 | public partial class AboutView : UserControl 6 | { 7 | public AboutView() 8 | { 9 | InitializeComponent(); 10 | 11 | Version pleasantUiVersion = typeof(PleasantTheme).Assembly.GetName().Version!; 12 | VersionTextBlock.Text = $"Version: {pleasantUiVersion.Major}.{pleasantUiVersion.Minor}.{pleasantUiVersion.Build}"; 13 | } 14 | } -------------------------------------------------------------------------------- /samples/PleasantUI.Example/Views/HomeView.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | 3 | namespace PleasantUI.Example.Views; 4 | 5 | public partial class HomeView : UserControl 6 | { 7 | public HomeView() => InitializeComponent(); 8 | } -------------------------------------------------------------------------------- /samples/PleasantUI.Example/Views/Pages/ControlPages/ButtonPageView.axaml: -------------------------------------------------------------------------------- 1 |  8 | 9 | 13 |