diff --git a/Directory.Packages.props b/Directory.Packages.props index e9bda3b..407c235 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -9,9 +9,11 @@ + + diff --git a/Lepo.i18n.sln b/Lepo.i18n.sln index 1a3fb04..e61ba76 100644 --- a/Lepo.i18n.sln +++ b/Lepo.i18n.sln @@ -30,7 +30,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Lepo.i18n.DependencyInjecti EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Lepo.i18n.Wpf.UnitTests", "tests\Lepo.i18n.Wpf.UnitTests\Lepo.i18n.Wpf.UnitTests.csproj", "{ED677E81-8D0F-42B2-A001-D37FEB3AAEA2}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lepo.i18n.Json.UnitTests", "tests\Lepo.i18n.Json.UnitTests\Lepo.i18n.Json.UnitTests.csproj", "{46BB2EDE-5A5C-46BC-930F-F1FB6128B4AE}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Lepo.i18n.Json.UnitTests", "tests\Lepo.i18n.Json.UnitTests\Lepo.i18n.Json.UnitTests.csproj", "{46BB2EDE-5A5C-46BC-930F-F1FB6128B4AE}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Galery", "src\Sample\Galery\Galery.csproj", "{9C513AB3-9C79-4D4B-BCDA-37621B2DAF1C}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -70,6 +72,10 @@ Global {46BB2EDE-5A5C-46BC-930F-F1FB6128B4AE}.Debug|Any CPU.Build.0 = Debug|Any CPU {46BB2EDE-5A5C-46BC-930F-F1FB6128B4AE}.Release|Any CPU.ActiveCfg = Release|Any CPU {46BB2EDE-5A5C-46BC-930F-F1FB6128B4AE}.Release|Any CPU.Build.0 = Release|Any CPU + {9C513AB3-9C79-4D4B-BCDA-37621B2DAF1C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9C513AB3-9C79-4D4B-BCDA-37621B2DAF1C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9C513AB3-9C79-4D4B-BCDA-37621B2DAF1C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9C513AB3-9C79-4D4B-BCDA-37621B2DAF1C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/Sample/Galery/App.xaml b/src/Sample/Galery/App.xaml new file mode 100644 index 0000000..3db73e4 --- /dev/null +++ b/src/Sample/Galery/App.xaml @@ -0,0 +1,17 @@ + + + + LeftToRight + + + + + + + diff --git a/src/Sample/Galery/App.xaml.cs b/src/Sample/Galery/App.xaml.cs new file mode 100644 index 0000000..505ac5a --- /dev/null +++ b/src/Sample/Galery/App.xaml.cs @@ -0,0 +1,112 @@ +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. +// Copyright (C) Leszek Pomianowski and Lepo.i18n Contributors. +// All Rights Reserved. + +using Galery.Services; +using Galery.ViewModels.Pages; +using Galery.ViewModels.Windows; +using Galery.Views.Pages; +using Galery.Views.Windows; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Lepo.i18n.DependencyInjection; +using Lepo.i18n.Json; +using System.IO; +using System.Reflection; +using System.Windows.Threading; +using Wpf.Ui; +using System.Globalization; +using Newtonsoft.Json; +using Galery.Models; + +namespace Galery; +/// +/// Interaction logic for App.xaml +/// +public partial class App +{ + // The.NET Generic Host provides dependency injection, configuration, logging, and other services. + // https://docs.microsoft.com/dotnet/core/extensions/generic-host + // https://docs.microsoft.com/dotnet/core/extensions/dependency-injection + // https://docs.microsoft.com/dotnet/core/extensions/configuration + // https://docs.microsoft.com/dotnet/core/extensions/logging + private static readonly IHost _host = Host + .CreateDefaultBuilder() + .ConfigureAppConfiguration(c => { c.SetBasePath(Path.GetDirectoryName(Assembly.GetEntryAssembly()!.Location)); }) + .ConfigureServices((context, services) => + { + _ = services.AddStringLocalizer(b => + { + _ = b.FromJson(Assembly.GetExecutingAssembly(), "Resources.Translations-fa-IR.json", new CultureInfo("fa-IR")); + _ = b.FromJson(Assembly.GetExecutingAssembly(), "Resources.Translations-en-US.json", new CultureInfo("en-US")); + var cul = new CultureInfo((JsonConvert.DeserializeObject(File.ReadAllText(@"CultureInfos.json")).CultureInfo)); + b.SetCulture(cul); + Application.Current.Resources["MainDirection"] = cul.EnglishName == "English (United States)" ? FlowDirection.LeftToRight : FlowDirection.RightToLeft; + }); + + + _ = services.AddHostedService(); + + // Page resolver service + _ = services.AddSingleton(); + + // Theme manipulation + _ = services.AddSingleton(); + + // TaskBar manipulation + _ = services.AddSingleton(); + + // Service containing navigation, same as INavigationWindow... but without window + _ = services.AddSingleton(); + + // Main window with navigation + _ = services.AddSingleton(); + _ = services.AddSingleton(); + + _ = services.AddSingleton(); + _ = services.AddSingleton(); + _ = services.AddTransient(); + _ = services.AddTransient(); + _ = services.AddSingleton(); + _ = services.AddSingleton(); + }).Build(); + + /// + /// Gets registered service. + /// + /// Type of the service to get. + /// Instance of the service or . + public static T GetService() + where T : class + { + return _host.Services.GetService(typeof(T)) as T; + } + + /// + /// Occurs when the application is loading. + /// + private void OnStartup(object sender, StartupEventArgs e) + { + _host.Start(); + } + + /// + /// Occurs when the application is closing. + /// + private async void OnExit(object sender, ExitEventArgs e) + { + await _host.StopAsync(); + + _host.Dispose(); + } + + /// + /// Occurs when an exception is thrown by an application but not handled. + /// + private void OnDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e) + { + // For more info see https://docs.microsoft.com/en-us/dotnet/api/system.windows.application.dispatcherunhandledexception?view=windowsdesktop-6.0 + } +} diff --git a/src/Sample/Galery/AssemblyInfo.cs b/src/Sample/Galery/AssemblyInfo.cs new file mode 100644 index 0000000..e170172 --- /dev/null +++ b/src/Sample/Galery/AssemblyInfo.cs @@ -0,0 +1,15 @@ +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. +// Copyright (C) Leszek Pomianowski and Lepo.i18n Contributors. +// All Rights Reserved. + +using System.Windows; + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located +//(used if a resource is not found in the page, +// app, or any theme specific resource dictionaries) +)] diff --git a/src/Sample/Galery/Assets/wpfui-icon-1024.png b/src/Sample/Galery/Assets/wpfui-icon-1024.png new file mode 100644 index 0000000..b70c4ed Binary files /dev/null and b/src/Sample/Galery/Assets/wpfui-icon-1024.png differ diff --git a/src/Sample/Galery/Assets/wpfui-icon-256.png b/src/Sample/Galery/Assets/wpfui-icon-256.png new file mode 100644 index 0000000..6b5cf5d Binary files /dev/null and b/src/Sample/Galery/Assets/wpfui-icon-256.png differ diff --git a/src/Sample/Galery/CultureInfos.json b/src/Sample/Galery/CultureInfos.json new file mode 100644 index 0000000..6fb058b --- /dev/null +++ b/src/Sample/Galery/CultureInfos.json @@ -0,0 +1,3 @@ +{ + "CultureInfo": "en-US" +} diff --git a/src/Sample/Galery/Galery.csproj b/src/Sample/Galery/Galery.csproj new file mode 100644 index 0000000..62f00ba --- /dev/null +++ b/src/Sample/Galery/Galery.csproj @@ -0,0 +1,51 @@ + + + + WinExe + net8.0-windows + app.manifest + wpfui-icon.ico + true + enable + enable + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Always + + + + diff --git a/src/Sample/Galery/Helpers/EnumToBooleanConverter.cs b/src/Sample/Galery/Helpers/EnumToBooleanConverter.cs new file mode 100644 index 0000000..c606087 --- /dev/null +++ b/src/Sample/Galery/Helpers/EnumToBooleanConverter.cs @@ -0,0 +1,39 @@ +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. +// Copyright (C) Leszek Pomianowski and Lepo.i18n Contributors. +// All Rights Reserved. + +using System.Globalization; +using System.Windows.Data; +using Wpf.Ui.Appearance; + +namespace Galery.Helpers; +internal class EnumToBooleanConverter : IValueConverter +{ + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (parameter is not String enumString) + { + throw new ArgumentException("ExceptionEnumToBooleanConverterParameterMustBeAnEnumName"); + } + + if (!Enum.IsDefined(typeof(ApplicationTheme), value)) + { + throw new ArgumentException("ExceptionEnumToBooleanConverterValueMustBeAnEnum"); + } + + var enumValue = Enum.Parse(typeof(ApplicationTheme), enumString); + + return enumValue.Equals(value); + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + if (parameter is not String enumString) + { + throw new ArgumentException("ExceptionEnumToBooleanConverterParameterMustBeAnEnumName"); + } + + return Enum.Parse(typeof(ApplicationTheme), enumString); + } +} diff --git a/src/Sample/Galery/Models/AppConfig.cs b/src/Sample/Galery/Models/AppConfig.cs new file mode 100644 index 0000000..f916b43 --- /dev/null +++ b/src/Sample/Galery/Models/AppConfig.cs @@ -0,0 +1,13 @@ +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. +// Copyright (C) Leszek Pomianowski and Lepo.i18n Contributors. +// All Rights Reserved. + +namespace Galery.Models; + +public class AppConfig +{ + public string ConfigurationsFolder { get; set; } + + public string AppPropertiesFileName { get; set; } +} diff --git a/src/Sample/Galery/Models/DataColor.cs b/src/Sample/Galery/Models/DataColor.cs new file mode 100644 index 0000000..7a0f3b5 --- /dev/null +++ b/src/Sample/Galery/Models/DataColor.cs @@ -0,0 +1,12 @@ +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. +// Copyright (C) Leszek Pomianowski and Lepo.i18n Contributors. +// All Rights Reserved. + +using System.Windows.Media; + +namespace Galery.Models; +public struct DataColor +{ + public Brush Color { get; set; } +} diff --git a/src/Sample/Galery/Models/LanInfo.cs b/src/Sample/Galery/Models/LanInfo.cs new file mode 100644 index 0000000..b106626 --- /dev/null +++ b/src/Sample/Galery/Models/LanInfo.cs @@ -0,0 +1,5 @@ +namespace Galery.Models; +public class LanInfo +{ + public string CultureInfo { get; set; } = default!; +} diff --git a/src/Sample/Galery/Resources/Translations-en-US.json b/src/Sample/Galery/Resources/Translations-en-US.json new file mode 100644 index 0000000..543e653 --- /dev/null +++ b/src/Sample/Galery/Resources/Translations-en-US.json @@ -0,0 +1,53 @@ +{ + "version": "1.0", + "strings": [ + { + "name": "Test", + "value": "Text in english" + }, + { + "name": "Titele", + "value": "WPF UI - Galery" + }, + { + "name": "Lan", + "value": "Language" + }, + { + "name": "Menu.Settings", + "value": "Settings" + }, + { + "name": "Menu.Dashboard", + "value": "Dashboard" + }, + { + "name": "Menu.Data", + "value": "Data" + }, + { + "name": "Menu.Search", + "value": "Search" + }, + { + "name": "Setting.Personalization", + "value": "Personalization" + }, + { + "name": "Setting.Theme", + "value": "Theme" + }, + { + "name": "Setting.Theme.Light", + "value": "Light" + }, + { + "name": "Setting.Theme.Dark", + "value": "Dark" + }, + { + "name": "Dashboard.Click", + "value": "ClickMe !" + } + ] +} \ No newline at end of file diff --git a/src/Sample/Galery/Resources/Translations-fa-IR.json b/src/Sample/Galery/Resources/Translations-fa-IR.json new file mode 100644 index 0000000..21622ba --- /dev/null +++ b/src/Sample/Galery/Resources/Translations-fa-IR.json @@ -0,0 +1,53 @@ +{ + "version": "1.0", + "strings": [ + { + "name": "Test", + "value": "متن برای فارسی" + }, + { + "name": "Titele", + "value": "WPF UI - گالری " + }, + { + "name": "Lan", + "value": "زبان سیستم" + }, + { + "name": "Menu.Settings", + "value": "تنظیمات" + }, + { + "name": "Menu.Dashboard", + "value": "داشبورد" + }, + { + "name": "Menu.Data", + "value": "دیتا" + }, + { + "name": "Menu.Search", + "value": "جستجو" + }, + { + "name": "Setting.Personalization", + "value": "شخصی سازی" + }, + { + "name": "Setting.Theme.Light", + "value": "روز" + }, + { + "name": "Setting.Theme", + "value": "تم قالب" + }, + { + "name": "Setting.Theme.Dark", + "value": "شب" + }, + { + "name": "Dashboard.Click", + "value": "! کلیک کنید" + } + ] +} \ No newline at end of file diff --git a/src/Sample/Galery/Resources/Translations.cs b/src/Sample/Galery/Resources/Translations.cs new file mode 100644 index 0000000..3405ed2 --- /dev/null +++ b/src/Sample/Galery/Resources/Translations.cs @@ -0,0 +1,10 @@ +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. +// Copyright (C) Leszek Pomianowski and Lepo.i18n Contributors. +// All Rights Reserved. + +namespace Galery.Resources; + +public partial class Translations +{ +} diff --git a/src/Sample/Galery/Services/ApplicationHostService.cs b/src/Sample/Galery/Services/ApplicationHostService.cs new file mode 100644 index 0000000..04f49bc --- /dev/null +++ b/src/Sample/Galery/Services/ApplicationHostService.cs @@ -0,0 +1,62 @@ +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. +// Copyright (C) Leszek Pomianowski and Lepo.i18n Contributors. +// All Rights Reserved. + +using Galery.Views.Pages; +using Galery.Views.Windows; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Wpf.Ui; + +namespace Galery.Services; +/// +/// Managed host of the application. +/// +public class ApplicationHostService : IHostedService +{ + private readonly IServiceProvider _serviceProvider; + + private INavigationWindow _navigationWindow; + + public ApplicationHostService(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } + + /// + /// Triggered when the application host is ready to start the service. + /// + /// Indicates that the start process has been aborted. + public async Task StartAsync(CancellationToken cancellationToken) + { + await HandleActivationAsync(); + } + + /// + /// Triggered when the application host is performing a graceful shutdown. + /// + /// Indicates that the shutdown process should no longer be graceful. + public async Task StopAsync(CancellationToken cancellationToken) + { + await Task.CompletedTask; + } + + /// + /// Creates main window during activation. + /// + private async Task HandleActivationAsync() + { + if (!Application.Current.Windows.OfType().Any()) + { + _navigationWindow = ( + _serviceProvider.GetService(typeof(INavigationWindow)) as INavigationWindow + )!; + _navigationWindow!.ShowWindow(); + + _navigationWindow.Navigate(typeof(Views.Pages.DashboardPage)); + } + + await Task.CompletedTask; + } +} diff --git a/src/Sample/Galery/Services/PageService.cs b/src/Sample/Galery/Services/PageService.cs new file mode 100644 index 0000000..626862f --- /dev/null +++ b/src/Sample/Galery/Services/PageService.cs @@ -0,0 +1,45 @@ +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. +// Copyright (C) Leszek Pomianowski and Lepo.i18n Contributors. +// All Rights Reserved. + +using Wpf.Ui; + +namespace Galery.Services; +/// +/// Service that provides pages for navigation. +/// +public class PageService : IPageService +{ + /// + /// Service which provides the instances of pages. + /// + private readonly IServiceProvider _serviceProvider; + + /// + /// Creates new instance and attaches the . + /// + public PageService(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } + + /// + public T? GetPage() + where T : class + { + if (!typeof(FrameworkElement).IsAssignableFrom(typeof(T))) + throw new InvalidOperationException("The page should be a WPF control."); + + return (T?)_serviceProvider.GetService(typeof(T)); + } + + /// + public FrameworkElement? GetPage(Type pageType) + { + if (!typeof(FrameworkElement).IsAssignableFrom(pageType)) + throw new InvalidOperationException("The page should be a WPF control."); + + return _serviceProvider.GetService(pageType) as FrameworkElement; + } +} diff --git a/src/Sample/Galery/Usings.cs b/src/Sample/Galery/Usings.cs new file mode 100644 index 0000000..c9c0526 --- /dev/null +++ b/src/Sample/Galery/Usings.cs @@ -0,0 +1,9 @@ +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. +// Copyright (C) Leszek Pomianowski and Lepo.i18n Contributors. +// All Rights Reserved. + +global using CommunityToolkit.Mvvm.ComponentModel; +global using CommunityToolkit.Mvvm.Input; +global using System; +global using System.Windows; diff --git a/src/Sample/Galery/ViewModels/Pages/DashboardViewModel.cs b/src/Sample/Galery/ViewModels/Pages/DashboardViewModel.cs new file mode 100644 index 0000000..f09b617 --- /dev/null +++ b/src/Sample/Galery/ViewModels/Pages/DashboardViewModel.cs @@ -0,0 +1,18 @@ +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. +// Copyright (C) Leszek Pomianowski and Lepo.i18n Contributors. +// All Rights Reserved. + +namespace Galery.ViewModels.Pages; + +public partial class DashboardViewModel : ObservableObject +{ + [ObservableProperty] + private int _counter = 0; + + [RelayCommand] + private void OnCounterIncrement() + { + Counter++; + } +} diff --git a/src/Sample/Galery/ViewModels/Pages/DataViewModel.cs b/src/Sample/Galery/ViewModels/Pages/DataViewModel.cs new file mode 100644 index 0000000..7f8102d --- /dev/null +++ b/src/Sample/Galery/ViewModels/Pages/DataViewModel.cs @@ -0,0 +1,50 @@ +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. +// Copyright (C) Leszek Pomianowski and Lepo.i18n Contributors. +// All Rights Reserved. + +using Galery.Models; +using System.Windows.Media; +using Wpf.Ui.Controls; + +namespace Galery.ViewModels.Pages; +public partial class DataViewModel : ObservableObject, INavigationAware +{ + private bool _isInitialized = false; + + [ObservableProperty] + private IEnumerable _colors; + + public void OnNavigatedTo() + { + if (!_isInitialized) + InitializeViewModel(); + } + + public void OnNavigatedFrom() { } + + private void InitializeViewModel() + { + var random = new Random(); + var colorCollection = new List(); + + for (int i = 0; i < 8192; i++) + colorCollection.Add( + new DataColor + { + Color = new SolidColorBrush( + Color.FromArgb( + (byte)200, + (byte)random.Next(0, 250), + (byte)random.Next(0, 250), + (byte)random.Next(0, 250) + ) + ) + } + ); + + Colors = colorCollection; + + _isInitialized = true; + } +} diff --git a/src/Sample/Galery/ViewModels/Pages/SettingsViewModel.cs b/src/Sample/Galery/ViewModels/Pages/SettingsViewModel.cs new file mode 100644 index 0000000..f048db3 --- /dev/null +++ b/src/Sample/Galery/ViewModels/Pages/SettingsViewModel.cs @@ -0,0 +1,104 @@ +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. +// Copyright (C) Leszek Pomianowski and Lepo.i18n Contributors. +// All Rights Reserved. + +using Microsoft.Extensions.Localization; +using Wpf.Ui.Appearance; +using Lepo.i18n; +using Wpf.Ui.Controls; +using Galery.Models; +using Newtonsoft.Json; +using System.IO; + +namespace Galery.ViewModels.Pages; +public partial class SettingsViewModel : ObservableObject, INavigationAware +{ + private bool _isInitialized = false; + + private readonly IStringLocalizer _stringLocalizer; + private readonly ILocalizationCultureManager _cultureManager; + + public SettingsViewModel(IStringLocalizer stringLocalizer, ILocalizationCultureManager cultureManager) + { + _stringLocalizer = stringLocalizer; + _cultureManager = cultureManager; + } + + [ObservableProperty] + private string _appVersion = String.Empty; + + [ObservableProperty] + private bool _isEnglish = true; + + [ObservableProperty] + private ApplicationTheme _currentTheme = ApplicationTheme.Unknown; + + public void OnNavigatedTo() + { + if (!_isInitialized) + InitializeViewModel(); + } + + public void OnNavigatedFrom() { } + + private void InitializeViewModel() + { + AppVersion = _stringLocalizer["Lan"].Value; + IsEnglish = _cultureManager.GetCulture().EnglishName == "English (United States)"; + CurrentTheme = ApplicationThemeManager.GetAppTheme(); + //AppVersion = $"UiDesktopApp1 - {GetAssemblyVersion()}"; + _isInitialized = true; + } + + private string GetAssemblyVersion() + { + return System.Reflection.Assembly.GetExecutingAssembly().GetName().Version?.ToString() + ?? String.Empty; + } + + [RelayCommand] + private void OnChangeTheme(string parameter) + { + switch (parameter) + { + case "theme_light": + if (CurrentTheme == ApplicationTheme.Light) + break; + + ApplicationThemeManager.Apply(ApplicationTheme.Light); + CurrentTheme = ApplicationTheme.Light; + + break; + + default: + if (CurrentTheme == ApplicationTheme.Dark) + break; + + ApplicationThemeManager.Apply(ApplicationTheme.Dark); + CurrentTheme = ApplicationTheme.Dark; + + break; + } + } + + [RelayCommand] + private void OnChangeLan(bool isChecked) + { + if (isChecked) + { + _cultureManager.SetCulture("en-US"); + File.WriteAllText(@"CultureInfos.json", JsonConvert.SerializeObject(new LanInfo() { CultureInfo = "en-US" })); + } + else + { + _cultureManager.SetCulture("fa-IR"); + File.WriteAllText(@"CultureInfos.json", JsonConvert.SerializeObject(new LanInfo() { CultureInfo = "fa-IR" })); + } + + AppVersion = _stringLocalizer["Lan"].Value; + + System.Diagnostics.Process.Start(System.Diagnostics.Process.GetCurrentProcess().ProcessName); + App.Current.Shutdown(); + } +} diff --git a/src/Sample/Galery/ViewModels/Windows/MainWindowViewModel.cs b/src/Sample/Galery/ViewModels/Windows/MainWindowViewModel.cs new file mode 100644 index 0000000..71917d0 --- /dev/null +++ b/src/Sample/Galery/ViewModels/Windows/MainWindowViewModel.cs @@ -0,0 +1,62 @@ +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. +// Copyright (C) Leszek Pomianowski and Lepo.i18n Contributors. +// All Rights Reserved. + +using Microsoft.Extensions.Localization; +using System.Collections.ObjectModel; +using Wpf.Ui.Controls; + +namespace Galery.ViewModels.Windows; +public partial class MainWindowViewModel : ObservableObject +{ + + private readonly IStringLocalizer _stringLocalizer; + + [ObservableProperty] + private string _applicationTitle = string.Empty; + + [ObservableProperty] + private ObservableCollection _menuItems; + + [ObservableProperty] + private ObservableCollection _footerMenuItems; + + [ObservableProperty] + private ObservableCollection _trayMenuItems = new() + { + new MenuItem { Header = "Home", Tag = "tray_home" } + }; + + public MainWindowViewModel(IStringLocalizer stringLocalizer) + { + _stringLocalizer = stringLocalizer; + ApplicationTitle = _stringLocalizer["Titele"].Value; + MenuItems = + [ + new NavigationViewItem() + { + Content = _stringLocalizer["Menu.Dashboard"].Value, + Icon = new SymbolIcon { Symbol = SymbolRegular.Home24 }, + TargetPageType = typeof(Views.Pages.DashboardPage) + }, + new NavigationViewItem() + { + Content =_stringLocalizer["Menu.Data"].Value, + Icon = new SymbolIcon { Symbol = SymbolRegular.DataHistogram24 }, + TargetPageType = typeof(Views.Pages.DataPage) + } + ]; + + FooterMenuItems = + [ + new NavigationViewItem() + { + Content = _stringLocalizer["Menu.Settings"].Value, + Icon = new SymbolIcon { Symbol = SymbolRegular.Settings24 }, + TargetPageType = typeof(Views.Pages.SettingsPage) + } + ]; + } + +} diff --git a/src/Sample/Galery/Views/Pages/DashboardPage.xaml b/src/Sample/Galery/Views/Pages/DashboardPage.xaml new file mode 100644 index 0000000..c7bff04 --- /dev/null +++ b/src/Sample/Galery/Views/Pages/DashboardPage.xaml @@ -0,0 +1,35 @@ + + + + + + + + + + + + diff --git a/src/Sample/Galery/Views/Pages/DashboardPage.xaml.cs b/src/Sample/Galery/Views/Pages/DashboardPage.xaml.cs new file mode 100644 index 0000000..0d86ca5 --- /dev/null +++ b/src/Sample/Galery/Views/Pages/DashboardPage.xaml.cs @@ -0,0 +1,21 @@ +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. +// Copyright (C) Leszek Pomianowski and Lepo.i18n Contributors. +// All Rights Reserved. + +using Galery.ViewModels.Pages; +using Wpf.Ui.Controls; + +namespace Galery.Views.Pages; +public partial class DashboardPage : INavigableView +{ + public DashboardViewModel ViewModel { get; } + + public DashboardPage(DashboardViewModel viewModel) + { + ViewModel = viewModel; + DataContext = this; + + InitializeComponent(); + } +} diff --git a/src/Sample/Galery/Views/Pages/DataPage.xaml b/src/Sample/Galery/Views/Pages/DataPage.xaml new file mode 100644 index 0000000..5854def --- /dev/null +++ b/src/Sample/Galery/Views/Pages/DataPage.xaml @@ -0,0 +1,27 @@ + + + + + + + diff --git a/src/Sample/Galery/Views/Pages/DataPage.xaml.cs b/src/Sample/Galery/Views/Pages/DataPage.xaml.cs new file mode 100644 index 0000000..ae156e8 --- /dev/null +++ b/src/Sample/Galery/Views/Pages/DataPage.xaml.cs @@ -0,0 +1,21 @@ +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. +// Copyright (C) Leszek Pomianowski and Lepo.i18n Contributors. +// All Rights Reserved. + +using Galery.ViewModels.Pages; +using Wpf.Ui.Controls; + +namespace Galery.Views.Pages; +public partial class DataPage : INavigableView +{ + public DataViewModel ViewModel { get; } + + public DataPage(DataViewModel viewModel) + { + ViewModel = viewModel; + DataContext = this; + + InitializeComponent(); + } +} diff --git a/src/Sample/Galery/Views/Pages/SettingsPage.xaml b/src/Sample/Galery/Views/Pages/SettingsPage.xaml new file mode 100644 index 0000000..f6d27d3 --- /dev/null +++ b/src/Sample/Galery/Views/Pages/SettingsPage.xaml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Sample/Galery/Views/Pages/SettingsPage.xaml.cs b/src/Sample/Galery/Views/Pages/SettingsPage.xaml.cs new file mode 100644 index 0000000..afce525 --- /dev/null +++ b/src/Sample/Galery/Views/Pages/SettingsPage.xaml.cs @@ -0,0 +1,21 @@ +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. +// Copyright (C) Leszek Pomianowski and Lepo.i18n Contributors. +// All Rights Reserved. + +using Galery.ViewModels.Pages; +using Wpf.Ui.Controls; + +namespace Galery.Views.Pages; +public partial class SettingsPage : INavigableView +{ + public SettingsViewModel ViewModel { get; } + + public SettingsPage(SettingsViewModel viewModel) + { + ViewModel = viewModel; + DataContext = this; + + InitializeComponent(); + } +} diff --git a/src/Sample/Galery/Views/Windows/MainWindow.xaml b/src/Sample/Galery/Views/Windows/MainWindow.xaml new file mode 100644 index 0000000..ec9c668 --- /dev/null +++ b/src/Sample/Galery/Views/Windows/MainWindow.xaml @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Sample/Galery/Views/Windows/MainWindow.xaml.cs b/src/Sample/Galery/Views/Windows/MainWindow.xaml.cs new file mode 100644 index 0000000..d9b27d5 --- /dev/null +++ b/src/Sample/Galery/Views/Windows/MainWindow.xaml.cs @@ -0,0 +1,67 @@ +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. +// Copyright (C) Leszek Pomianowski and Lepo.i18n Contributors. +// All Rights Reserved. + +using Galery.ViewModels.Windows; +using Wpf.Ui; +using Wpf.Ui.Appearance; +using Wpf.Ui.Controls; + +namespace Galery.Views.Windows; +public partial class MainWindow : INavigationWindow +{ + public MainWindowViewModel ViewModel { get; } + + public MainWindow( + MainWindowViewModel viewModel, + IPageService pageService, + INavigationService navigationService + ) + { + ViewModel = viewModel; + DataContext = this; + + SystemThemeWatcher.Watch(this); + + InitializeComponent(); + SetPageService(pageService); + + navigationService.SetNavigationControl(RootNavigation); + } + + #region INavigationWindow methods + + public INavigationView GetNavigation() => RootNavigation; + + public bool Navigate(Type pageType) => RootNavigation.Navigate(pageType); + + public void SetPageService(IPageService pageService) => RootNavigation.SetPageService(pageService); + + public void ShowWindow() => Show(); + + public void CloseWindow() => Close(); + + #endregion INavigationWindow methods + + /// + /// Raises the closed event. + /// + protected override void OnClosed(EventArgs e) + { + base.OnClosed(e); + + // Make sure that closing this window will begin the process of closing the application. + Application.Current.Shutdown(); + } + + INavigationView INavigationWindow.GetNavigation() + { + throw new NotImplementedException(); + } + + public void SetServiceProvider(IServiceProvider serviceProvider) + { + throw new NotImplementedException(); + } +} diff --git a/src/Sample/Galery/app.manifest b/src/Sample/Galery/app.manifest new file mode 100644 index 0000000..a6f917d --- /dev/null +++ b/src/Sample/Galery/app.manifest @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PerMonitor + true/PM + true + + + + + + + + + + diff --git a/src/Sample/Galery/wpfui-icon.ico b/src/Sample/Galery/wpfui-icon.ico new file mode 100644 index 0000000..cc128fd Binary files /dev/null and b/src/Sample/Galery/wpfui-icon.ico differ