diff --git a/src/Apps/Corathing.Organizer/App.xaml.cs b/src/Apps/Corathing.Organizer/App.xaml.cs index dd61080..b04690a 100644 --- a/src/Apps/Corathing.Organizer/App.xaml.cs +++ b/src/Apps/Corathing.Organizer/App.xaml.cs @@ -7,6 +7,8 @@ using Corathing.Contracts.Services; using Corathing.Dashboards.Services; +using Corathing.Dashboards.WPF.Services; +using Corathing.Organizer.Resources; using Corathing.Organizer.Services; using Corathing.Organizer.Utils; using Corathing.Organizer.ViewModels; @@ -57,6 +59,9 @@ protected override void OnStartup(StartupEventArgs e) Services = ConfigureServices(e.Args); + var appStateService = Services.GetService(); + var appSettings = appStateService.GetAppSettings(); + // Set the theme var theme = System.Configuration.ConfigurationManager.AppSettings["Theme"]; var themeService = Services.GetService(); @@ -104,6 +109,19 @@ protected override void OnStartup(StartupEventArgs e) //widgetService.RegisterWidgets(new List { new WidgetGenerator() }); + IAuthService authService = App.Current.Services.GetService(); + if (authService != null && authService.UseAuthService) + { + //var loginWindow = new BaseWindow(); + //loginWindow.Content = new LoginView(); + //loginWindow.Owner = Window.GetWindow(this); + //loginWindow.ShowDialog(); + //if (loginWindow.DialogResult == false) + //{ + // // System.Shutdown + //} + } + // Create a new MainWindow and set its DataContext to a new MainWindowViewModel which binds the view to the viewmodel new MainWindow().Show(); } @@ -136,11 +154,15 @@ private static IServiceProvider ConfigureServices(string[] args) serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); - //serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(LocalizationService.Instance); + + LocalizationService.Instance.RegisterStringResourceManager("Corathing.Organizer", + CorathingOrganizerLocalizationStringResources.ResourceManager); // Register viewmodels serviceCollection.AddScoped(); serviceCollection.AddScoped(); + serviceCollection.AddScoped(); //Logger.Configure(configuration); //serviceCollection.AddSingleton(); diff --git a/src/Apps/Corathing.Organizer/Behaviors/DataTemplateSelector.cs b/src/Apps/Corathing.Organizer/Behaviors/DataTemplateSelector.cs new file mode 100644 index 0000000..1941138 --- /dev/null +++ b/src/Apps/Corathing.Organizer/Behaviors/DataTemplateSelector.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows; + +namespace Corathing.Organizer.Behaviors; + +public class TemplateSelector : DataTemplateSelector +{ + public DataTemplate ItemTemplate { get; set; } + public DataTemplate NewButtonTemplate { get; set; } + + public override DataTemplate SelectTemplate(object item, DependencyObject container) + { + if (item == CollectionView.NewItemPlaceholder) + { + return NewButtonTemplate; + } + else + { + return ItemTemplate; + } + } +} diff --git a/src/Apps/Corathing.Organizer/Converters/ApplicationLanguageToCultureInfoConverter.cs b/src/Apps/Corathing.Organizer/Converters/ApplicationLanguageToCultureInfoConverter.cs new file mode 100644 index 0000000..c1cea37 --- /dev/null +++ b/src/Apps/Corathing.Organizer/Converters/ApplicationLanguageToCultureInfoConverter.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Data; + +using Corathing.Contracts.Services; +using Corathing.Dashboards.WPF.Bindings; + +namespace Corathing.Organizer.Converters; + +[ValueConversion(typeof(ApplicationLanguage), typeof(CultureInfo))] +public class ApplicationLanguageToCultureInfoConverter : IValueConverter +{ + public object? Convert(object value, Type targetType, + object parameter, CultureInfo culture) + => value is ApplicationLanguage language ? language switch + { + ApplicationLanguage.en_US => 0, + ApplicationLanguage.ko_KR => 1, + _ => 0, + } : 0; + + public object? ConvertBack(object value, Type targetType, + object parameter, CultureInfo culture) + => value is int index ? index switch + { + 0 => ApplicationLanguage.en_US, + 1 => ApplicationLanguage.ko_KR, + _ => ApplicationLanguage.en_US, + } : ApplicationLanguage.en_US; + + //public object? Convert(object value, Type targetType, + // object parameter, CultureInfo culture) + //{ + // if (value == null) + // return null; + // if (value is not AvailableCulture) + // return null; + // return Convert((AvailableCulture)value); + //} + + //public object? ConvertBack(object value, Type targetType, + // object parameter, CultureInfo culture) + //{ + // if (value == null) + // return null; + // if (value is not CultureInfo) + // return null; + // return ConvertBack((CultureInfo)value); + //} + + //public static CultureInfo Convert(AvailableCulture culture) + //{ + // return CultureInfo.GetCultureInfo( + // StringToAvailableCultureConverter. + // ConvertBack(culture)); + //} + + //public static AvailableCulture ConvertBack(CultureInfo culture) + //{ + // return StringToAvailableCultureConverter.Convert(culture.Name); + //} +} diff --git a/src/Apps/Corathing.Organizer/Converters/ApplicationLanguageToIndexConverter.cs b/src/Apps/Corathing.Organizer/Converters/ApplicationLanguageToIndexConverter.cs new file mode 100644 index 0000000..75ecbdb --- /dev/null +++ b/src/Apps/Corathing.Organizer/Converters/ApplicationLanguageToIndexConverter.cs @@ -0,0 +1,29 @@ +using System; +using System.Globalization; +using System.Windows.Data; + +using Corathing.Contracts.Services; + +namespace Corathing.Organizer.Converters; + +[ValueConversion(typeof(ApplicationLanguage), typeof(int))] +public class ApplicationLanguageToIndexConverter : IValueConverter +{ + public object? Convert(object value, Type targetType, + object parameter, CultureInfo culture) + => value is ApplicationLanguage language ? language switch + { + ApplicationLanguage.en_US => 0, + ApplicationLanguage.ko_KR => 1, + _ => 0, + } : 0; + + public object? ConvertBack(object value, Type targetType, + object parameter, CultureInfo culture) + => value is int index ? index switch + { + 0 => ApplicationLanguage.en_US, + 1 => ApplicationLanguage.ko_KR, + _ => ApplicationLanguage.en_US, + } : ApplicationLanguage.en_US; +} diff --git a/src/Apps/Corathing.Organizer/Converters/UILanguageToIndexConverter.cs b/src/Apps/Corathing.Organizer/Converters/UILanguageToIndexConverter.cs new file mode 100644 index 0000000..a6ec5e1 --- /dev/null +++ b/src/Apps/Corathing.Organizer/Converters/UILanguageToIndexConverter.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Data; + +using Corathing.Contracts.Services; + +namespace Corathing.Organizer.Converters; + +public class UILanguageToIndexConverter : IValueConverter +{ + public object? Convert(object value, Type targetType, + object parameter, CultureInfo culture) + => value is string languageName ? languageName switch + { + "English" => 0, + "한국어" => 1, + _ => 0, + } : 0; + + public object? ConvertBack(object value, Type targetType, + object parameter, CultureInfo culture) + => value is int index ? index switch + { + 0 => "English", + 1 => "한국어", + _ => "English", + } : "English"; +} diff --git a/src/Apps/Corathing.Organizer/Corathing.Organizer.csproj b/src/Apps/Corathing.Organizer/Corathing.Organizer.csproj index 9d0e7c2..24a0d05 100644 --- a/src/Apps/Corathing.Organizer/Corathing.Organizer.csproj +++ b/src/Apps/Corathing.Organizer/Corathing.Organizer.csproj @@ -43,4 +43,25 @@ + + + True + True + CorathingOrganizerLocalizationStringResources.resx + + + + + + PublicResXFileCodeGenerator + CorathingOrganizerLocalizationStringResources.Designer.cs + + + + + + Always + + + diff --git a/src/Apps/Corathing.Organizer/Extensions/WindowExtensions.cs b/src/Apps/Corathing.Organizer/Extensions/WindowExtensions.cs index 1e360e2..54e5205 100644 --- a/src/Apps/Corathing.Organizer/Extensions/WindowExtensions.cs +++ b/src/Apps/Corathing.Organizer/Extensions/WindowExtensions.cs @@ -156,7 +156,7 @@ public static void MinimizeWindow(this MetroWindow window) window.WindowState = WindowState.Minimized; } - public static void CenterWindowToParent(this MetroWindow window) + public static void CenterWindowToParent(this Window window) { if (window.Owner == null) return; @@ -165,6 +165,15 @@ public static void CenterWindowToParent(this MetroWindow window) window.WindowStartupLocation = WindowStartupLocation.CenterOwner; if (window.IsLoaded) + { window.WindowState = WindowState.Normal; + + if (window.Owner != null) + { + Window parent = window.Owner; + window.Left = parent.Left + (parent.ActualWidth - window.ActualWidth) / 2; + window.Top = parent.Top + (parent.ActualHeight - window.ActualHeight) / 2; + } + } } } diff --git a/src/Apps/Corathing.Organizer/MainWindow.xaml b/src/Apps/Corathing.Organizer/MainWindow.xaml index 68906c1..31880ce 100644 --- a/src/Apps/Corathing.Organizer/MainWindow.xaml +++ b/src/Apps/Corathing.Organizer/MainWindow.xaml @@ -14,6 +14,7 @@ ShowMaxRestoreButton="False" ShowCloseButton="False" IsWindowDraggable="True" + WindowStartupLocation="CenterScreen" Height="1000" Width="1600"> diff --git a/src/Apps/Corathing.Organizer/Models/ProjectContext.cs b/src/Apps/Corathing.Organizer/Models/ProjectContext.cs index 0438b4c..58906c8 100644 --- a/src/Apps/Corathing.Organizer/Models/ProjectContext.cs +++ b/src/Apps/Corathing.Organizer/Models/ProjectContext.cs @@ -1,11 +1,14 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.ComponentModel; using System.Linq; using System.Text; using System.Threading.Tasks; +using System.Windows.Data; using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; namespace Corathing.Organizer.Models; @@ -19,16 +22,58 @@ public partial class ProjectContext : ObservableObject [ObservableProperty] private string _title; + [DefaultValue(false)] + [ObservableProperty] + private bool? _editMode; + /// - /// Gets or sets the workflows. + /// Gets or sets the dashboards. /// - /// The widgets. + /// The dashboards. + private ObservableCollection? _workflows; + public ObservableCollection Workflows + { + get => _workflows; + set + { + if (EqualityComparer?>.Default.Equals(_workflows, value)) + return; + OnPropertyChanging(nameof(Workflows)); + _workflows = value; + var itemsView = (IEditableCollectionView)CollectionViewSource.GetDefaultView(_workflows); + itemsView.NewItemPlaceholderPosition = NewItemPlaceholderPosition.AtEnd; + OnPropertyChanged(nameof(Workflows)); + } + } + [ObservableProperty] - private ObservableCollection _workflows; + private WorkflowContext _selectedWorkflow; + + [RelayCommand] + public void AddWorkflow() + { + var newWorkflow = new WorkflowContext(); + Workflows.Add(newWorkflow); + SelectedWorkflow = newWorkflow; + } + #endregion public ProjectContext() { Workflows = new ObservableCollection(); } + + protected override void OnPropertyChanged(PropertyChangedEventArgs e) + { + base.OnPropertyChanged(e); + + if (Workflows != null) + { + foreach (var workflow in Workflows) + { + workflow.EditMode = EditMode; + } + } + } } diff --git a/src/Apps/Corathing.Organizer/Models/WorkflowContext.cs b/src/Apps/Corathing.Organizer/Models/WorkflowContext.cs index f5a4fa6..8302401 100644 --- a/src/Apps/Corathing.Organizer/Models/WorkflowContext.cs +++ b/src/Apps/Corathing.Organizer/Models/WorkflowContext.cs @@ -1,12 +1,22 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.ComponentModel; using System.Linq; using System.Text; using System.Threading.Tasks; +using System.Windows; +using System.Windows.Input; +using System.Windows.Media.Effects; + using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; using Corathing.Contracts.Bases; +using Corathing.Dashboards.WPF.Controls; +using Corathing.Organizer.Controls; +using Corathing.Organizer.Extensions; +using Corathing.Organizer.Views; namespace Corathing.Organizer.Models; @@ -41,6 +51,14 @@ public partial class WorkflowContext : ObservableObject [ObservableProperty] private string _title; + [DefaultValue(false)] + [ObservableProperty] + private bool? _isPlaceholder; + + [DefaultValue(false)] + [ObservableProperty] + private bool? _editMode; + /// /// Gets or sets the widgets. /// @@ -77,6 +95,37 @@ public partial class WorkflowContext : ObservableObject // return Task.CompletedTask; //} + /// + /// Gets the command remove widget. + /// + /// The command remove widget. + [RelayCommand] + public void RemoveWidget(WidgetHost widget) + { + Widgets.Remove(widget.DataContext as WidgetContext); + } + + [RelayCommand] + public void ConfigureWidget(WidgetHost widget) + { + var widgetHost = widget; + var parentWindow = Window.GetWindow(widgetHost); + var window = new BaseWindow(); + if (parentWindow != null) + { + window.Owner = parentWindow; + parentWindow.Effect = new BlurEffect(); + window.CenterWindowToParent(); + } + var view = new WidgetSettingsView(widgetHost); + window.Content = view; + window.ShowDialog(); + if (parentWindow != null) + { + parentWindow.Effect = null; + } + } + public WorkflowContext() { Widgets = new ObservableCollection(); diff --git a/src/Apps/Corathing.Organizer/Resources/CorathingOrganizerLocalizationStringResources.Designer.cs b/src/Apps/Corathing.Organizer/Resources/CorathingOrganizerLocalizationStringResources.Designer.cs new file mode 100644 index 0000000..c60e8ee --- /dev/null +++ b/src/Apps/Corathing.Organizer/Resources/CorathingOrganizerLocalizationStringResources.Designer.cs @@ -0,0 +1,207 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Corathing.Organizer.Resources { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + public class CorathingOrganizerLocalizationStringResources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal CorathingOrganizerLocalizationStringResources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Corathing.Organizer.Resources.CorathingOrganizerLocalizationStringResources", typeof(CorathingOrganizerLocalizationStringResources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to . + /// + public static string Corathing_Organizer_AppLanguage { + get { + return ResourceManager.GetString("Corathing.Organizer.AppLanguage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to . + /// + public static string Corathing_Organizer_AppLanguageDescription { + get { + return ResourceManager.GetString("Corathing.Organizer.AppLanguageDescription", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to . + /// + public static string Corathing_Organizer_AppTheme { + get { + return ResourceManager.GetString("Corathing.Organizer.AppTheme", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to . + /// + public static string Corathing_Organizer_AppThemeDescription { + get { + return ResourceManager.GetString("Corathing.Organizer.AppThemeDescription", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to . + /// + public static string Corathing_Organizer_CurrentConfigureFile { + get { + return ResourceManager.GetString("Corathing.Organizer.CurrentConfigureFile", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to . + /// + public static string Corathing_Organizer_CurrentConfigureFileDescription { + get { + return ResourceManager.GetString("Corathing.Organizer.CurrentConfigureFileDescription", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to . + /// + public static string Corathing_Organizer_Dark { + get { + return ResourceManager.GetString("Corathing.Organizer.Dark", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to . + /// + public static string Corathing_Organizer_Light { + get { + return ResourceManager.GetString("Corathing.Organizer.Light", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to . + /// + public static string Corathing_Organizer_ManageCorathingAppConfigurationFile { + get { + return ResourceManager.GetString("Corathing.Organizer.ManageCorathingAppConfigurationFile", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to . + /// + public static string Corathing_Organizer_Settings { + get { + return ResourceManager.GetString("Corathing.Organizer.Settings", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to . + /// + public static string Corathing_Organizer_UseApplicationFolder { + get { + return ResourceManager.GetString("Corathing.Organizer.UseApplicationFolder", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to . + /// + public static string Corathing_Organizer_UseApplicationFolderDescription { + get { + return ResourceManager.GetString("Corathing.Organizer.UseApplicationFolderDescription", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to . + /// + public static string Corathing_Organizer_UseGlobalConfigurationFolder { + get { + return ResourceManager.GetString("Corathing.Organizer.UseGlobalConfigurationFolder", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to . + /// + public static string Corathing_Organizer_UseGlobalConfigurationFolderDescription { + get { + return ResourceManager.GetString("Corathing.Organizer.UseGlobalConfigurationFolderDescription", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to . + /// + public static string Corathing_Organizer_UseUserCustomFile { + get { + return ResourceManager.GetString("Corathing.Organizer.UseUserCustomFile", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to . + /// + public static string Corathing_Organizer_UseUserCustomFolderDescription { + get { + return ResourceManager.GetString("Corathing.Organizer.UseUserCustomFolderDescription", resourceCulture); + } + } + } +} diff --git a/src/Apps/Corathing.Organizer/Resources/CorathingOrganizerLocalizationStringResources.en-US.resx b/src/Apps/Corathing.Organizer/Resources/CorathingOrganizerLocalizationStringResources.en-US.resx new file mode 100644 index 0000000..8bae13d --- /dev/null +++ b/src/Apps/Corathing.Organizer/Resources/CorathingOrganizerLocalizationStringResources.en-US.resx @@ -0,0 +1,168 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Settings + + + Light + + + Dark + + + App Theme + + + Select which app theme to display + + + App Language + + + Select which app language to display + + + Manage App Configuration File + + + Load and save global settings, app path, and user settings. + + + Current Configuration File + + + Use Global Configuration Folder + + + Use Application Folder + + + Use Custom File + + + (TBA) Use a folder that stores settings applicable to all users and programs. + + + Use a folder that stores settings and data specific to the application. + + + Use a file where individual users can store their personalized settings. + + \ No newline at end of file diff --git a/src/Apps/Corathing.Organizer/Resources/CorathingOrganizerLocalizationStringResources.ko-KR.resx b/src/Apps/Corathing.Organizer/Resources/CorathingOrganizerLocalizationStringResources.ko-KR.resx new file mode 100644 index 0000000..91fec31 --- /dev/null +++ b/src/Apps/Corathing.Organizer/Resources/CorathingOrganizerLocalizationStringResources.ko-KR.resx @@ -0,0 +1,168 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 설정 + + + 밝은 테마 + + + 어두운 테마 + + + 앱 테마 + + + 화면에 표시하기 위한 앱 테마를 선택하세요. + + + 앱 언어 + + + 화면에 표시하기 위한 앱 언어를 선택하세요. + + + 앱 환경설정 파일 관리 + + + 현재 설정 파일 + + + 전역 설정, 앱 설정, 사용자 설정을 불러오고 저장하세요. + + + 전역 환경 폴더 사용 + + + 애플리케이션 폴더 사용 + + + 사용자 지정 파일 사용 + + + (현재 미지원) 모든 사용자와 프로그램에 적용되는 설정을 저장하는 폴더로 설정하세요. + + + 해당 프로그램 전용 설정 및 데이터를 저장하는 폴더로 설정하세요. + + + 개별 사용자가 자신의 필요에 맞게 설정을 저장하는 파일로 설정하세요. + + \ No newline at end of file diff --git a/src/Apps/Corathing.Organizer/Resources/CorathingOrganizerLocalizationStringResources.resx b/src/Apps/Corathing.Organizer/Resources/CorathingOrganizerLocalizationStringResources.resx new file mode 100644 index 0000000..29e3e1d --- /dev/null +++ b/src/Apps/Corathing.Organizer/Resources/CorathingOrganizerLocalizationStringResources.resx @@ -0,0 +1,148 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Apps/Corathing.Organizer/Services/AppStateService.cs b/src/Apps/Corathing.Organizer/Services/AppStateService.cs index abf5952..0a4af53 100644 --- a/src/Apps/Corathing.Organizer/Services/AppStateService.cs +++ b/src/Apps/Corathing.Organizer/Services/AppStateService.cs @@ -1,16 +1,36 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text; +using System.Text.Json; +using System.Text.Json.Nodes; +using System.Text.Json.Serialization; +using System.Text.Json.Serialization.Metadata; using System.Threading.Tasks; using Corathing.Contracts.Bases; +using Corathing.Contracts.Factories; using Corathing.Contracts.Services; namespace Corathing.Organizer.Services; public class AppStateService : IAppStateService { + private AppSettings _cachedAppSettings; + private AppState _cachedAppState; + + private JsonSerializerOptions _serializerOptions = new JsonSerializerOptions() + { + TypeInfoResolver = new DefaultJsonTypeInfoResolver(), + WriteIndented = true, + }; + + private JsonWriterOptions _writerOptions = new JsonWriterOptions + { + Indented = true + }; + public bool TryGetProject(Guid id, out ProjectState project) { project = new ProjectState(); @@ -29,8 +49,66 @@ public bool TryGetWorkflow(Guid id, out WorkflowState workflow) return true; } - public void Update(string key, string value) + public AppSettings GetAppSettings() + { + ReadAppSettingsFromAppPath(); + return _cachedAppSettings.Copy(); + } + + + /// + /// Update Key and Value AppSettings + /// + /// + /// + /// + public void UpdateAppSettings(AppSettings appSettings) + { + _cachedAppSettings = appSettings; + WriteAppSettingsToAppPath(appSettings); + + // Read or Create AppState Data + if (_cachedAppSettings.UseGlobalConfiguration ?? false) + { + ReadOrCreateAppState(Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), + "corathing-widgetsettings.json" + )); + } + else if (_cachedAppSettings.UseAppPathConfiguration ?? false) + { + ReadOrCreateAppState("corathing-widgetsettings.json"); + } + else if (!string.IsNullOrEmpty(_cachedAppSettings.CustomPath)) + { + ReadOrCreateAppState(_cachedAppSettings.CustomPath); + } + else + { + ReadOrCreateAppState("corathing-widgetsettings.json"); + } + } + + private void ReadOrCreateAppState(string path) { + if (!File.Exists(path)) + { + if (!Directory.Exists(Path.GetDirectoryName(Path.GetFullPath(path)))) + { + Directory.CreateDirectory(Path.GetDirectoryName(Path.GetFullPath(path))); + } + using var streamWriter = File.CreateText(path); + var appState = AppStateFactory.Create(); + var json = JsonSerializer.Serialize(appState); + streamWriter.Write(json); + } + else + { + var json = File.ReadAllText(path); + using var document = JsonDocument.Parse(json, + new JsonDocumentOptions { CommentHandling = JsonCommentHandling.Skip }); + _cachedAppState = document.RootElement.Deserialize(); + } } public void UpdateOrAdd(Guid id, object value) @@ -40,4 +118,40 @@ public void UpdateOrAdd(Guid id, object value) public void UpdateOverwrite(Guid id, object value) { } + + #region Private Methods + private AppSettings ReadAppSettingsFromAppPath() + { + if (_cachedAppSettings != null) + return _cachedAppSettings; + + var filePath = "appsettings.json"; + var json = File.ReadAllText(filePath); + using var document = JsonDocument.Parse(json, new JsonDocumentOptions { CommentHandling = JsonCommentHandling.Skip }); + var appSettings = document.RootElement + .GetProperty("Corathing") + .GetProperty("Organizer") + .Deserialize(); + _cachedAppSettings = appSettings; + return appSettings; + } + + private async void WriteAppSettingsToAppPath(AppSettings appSettings) + { + if (appSettings == null) + return; + + var filePath = "appsettings.json"; + + string jsonString = await File.ReadAllTextAsync(filePath); + + var rootNode = JsonNode.Parse(jsonString); + + rootNode["Corathing"]["Organizer"].ReplaceWith(appSettings); + var json = rootNode.ToJsonString(_serializerOptions); + + await File.WriteAllTextAsync(filePath, json); + } + + #endregion } diff --git a/src/Apps/Corathing.Organizer/Services/ThemeService.cs b/src/Apps/Corathing.Organizer/Services/ThemeService.cs index b4ab102..06e78af 100644 --- a/src/Apps/Corathing.Organizer/Services/ThemeService.cs +++ b/src/Apps/Corathing.Organizer/Services/ThemeService.cs @@ -23,7 +23,7 @@ public class ThemeInfo public class ThemeService : IThemeService { #region Private Properties - private readonly IServiceProvider _serivces; + private readonly IServiceProvider? _serivces; private ApplicationTheme _cachedApplicationTheme = ApplicationTheme.Unknown; private SystemTheme _cachedSystemTheme = SystemTheme.Unknown; public List ThemeInfos = new List(); diff --git a/src/Apps/Corathing.Organizer/Styles/CustomStyles.xaml b/src/Apps/Corathing.Organizer/Styles/CustomStyles.xaml new file mode 100644 index 0000000..7a31ead --- /dev/null +++ b/src/Apps/Corathing.Organizer/Styles/CustomStyles.xaml @@ -0,0 +1,37 @@ + + + + \ No newline at end of file diff --git a/src/Apps/Corathing.Organizer/Utils/JsonUtils.cs b/src/Apps/Corathing.Organizer/Utils/JsonUtils.cs new file mode 100644 index 0000000..59dda51 --- /dev/null +++ b/src/Apps/Corathing.Organizer/Utils/JsonUtils.cs @@ -0,0 +1,125 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Text.Json; +using System.Threading.Tasks; + +namespace Corathing.Organizer.Utils; + +public static class JsonUtils +{ + public static void PopulateObject(T target, string jsonSource) where T : class => + PopulateObject(target, jsonSource, typeof(T)); + + public static void OverwriteProperty(T target, JsonProperty updatedProperty) where T : class => + OverwriteProperty(target, updatedProperty, typeof(T)); + + private static void PopulateObject(object target, string jsonSource, Type type) + { + var json = JsonDocument.Parse(jsonSource).RootElement; + + foreach (var property in json.EnumerateObject()) + { + OverwriteProperty(target, property, type); + } + } + + private static void PopulateCollection(object target, string jsonSource, Type elementType) + { + var json = JsonDocument.Parse(jsonSource).RootElement; + var addMethod = target.GetType().GetMethod("Add", new[] { elementType }); + var containsMethod = target.GetType().GetMethod("Contains", new[] { elementType }); + + foreach (var property in json.EnumerateArray()) + { + object? element; + + if (elementType.IsValueType || elementType == typeof(string)) + { + element = JsonSerializer.Deserialize(jsonSource, elementType); + } + else if (IsCollection(elementType)) + { + var nestedElementType = elementType.GenericTypeArguments[0]; + element = Instantiate(elementType); + + PopulateCollection(element, property.GetRawText(), nestedElementType); + } + else + { + element = Instantiate(elementType); + + PopulateObject(element, property.GetRawText(), elementType); + } + + var contains = containsMethod.Invoke(target, new[] { element }); + if (contains is false) + { + addMethod.Invoke(target, new[] { element }); + } + } + } + + private static void OverwriteProperty(object target, JsonProperty updatedProperty, Type type) + { + var propertyInfo = type.GetProperty(updatedProperty.Name); + + if (propertyInfo == null) + { + return; + } + + if (updatedProperty.Value.ValueKind == JsonValueKind.Null) + { + propertyInfo.SetValue(target, null); + return; + } + + var propertyType = propertyInfo.PropertyType; + object? parsedValue; + + if (propertyType.IsValueType || propertyType == typeof(string)) + { + parsedValue = JsonSerializer.Deserialize( + updatedProperty.Value.GetRawText(), + propertyType); + } + else if (IsCollection(propertyType)) + { + var elementType = propertyType.GenericTypeArguments[0]; + parsedValue = propertyInfo.GetValue(target); + parsedValue ??= Instantiate(propertyType); + + PopulateCollection(parsedValue, updatedProperty.Value.GetRawText(), elementType); + } + else + { + parsedValue = propertyInfo.GetValue(target); + parsedValue ??= Instantiate(propertyType); + + PopulateObject( + parsedValue, + updatedProperty.Value.GetRawText(), + propertyType); + } + + propertyInfo.SetValue(target, parsedValue); + } + + private static object Instantiate(Type type) + { + var ctor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, Array.Empty()); + + if (ctor is null) + { + throw new InvalidOperationException($"Type {type.Name} has no parameterless constructor."); + } + + return ctor.Invoke(Array.Empty()); + } + + private static bool IsCollection(Type type) => + type.GetInterfaces().Any(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(ICollection<>)); +} diff --git a/src/Apps/Corathing.Organizer/ViewModels/DashboardViewModel.cs b/src/Apps/Corathing.Organizer/ViewModels/DashboardViewModel.cs index e452080..488bdd3 100644 --- a/src/Apps/Corathing.Organizer/ViewModels/DashboardViewModel.cs +++ b/src/Apps/Corathing.Organizer/ViewModels/DashboardViewModel.cs @@ -1,10 +1,12 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.ComponentModel; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; +using System.Windows.Data; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Effects; @@ -19,9 +21,10 @@ using Corathing.Organizer.Extensions; using Corathing.Organizer.Models; using Corathing.Organizer.Views; - using Microsoft.Extensions.DependencyInjection; +using static MaterialDesignThemes.Wpf.Theme.ToolBar; + namespace Corathing.Organizer.ViewModels; /// @@ -42,11 +45,27 @@ public partial class DashboardsViewModel : ObservableObject, IDashboardConfigura /// Gets or sets the dashboards. /// /// The dashboards. + private ObservableCollection? _workflows; + public ObservableCollection Workflows + { + get => _workflows; + set + { + if (EqualityComparer?>.Default.Equals(_workflows, value)) + return; + OnPropertyChanging(nameof(Workflows)); + _workflows = value; + var itemsView = (IEditableCollectionView)CollectionViewSource.GetDefaultView(_workflows); + itemsView.NewItemPlaceholderPosition = NewItemPlaceholderPosition.AtEnd; + OnPropertyChanged(nameof(Workflows)); + } + } + [ObservableProperty] - private ObservableCollection? _dashboards; + private ProjectContext _selectedProject; [ObservableProperty] - private WorkflowContext _selectedDashboard; + private WorkflowContext _selectedWorkflow; [ObservableProperty] private ObservableCollection _addWidgetMenuItemViewModels; @@ -69,6 +88,19 @@ public partial class DashboardsViewModel : ObservableObject, IDashboardConfigura #region Public Properties + protected override void OnPropertyChanged(PropertyChangedEventArgs e) + { + base.OnPropertyChanged(e); + + if (Projects != null) + { + foreach (var project in Projects) + { + project.EditMode = EditMode; + } + } + } + /// /// Gets the command add widget. /// @@ -77,14 +109,20 @@ public partial class DashboardsViewModel : ObservableObject, IDashboardConfigura { var widgetGeneratorToAdd = (WidgetGenerator)o; - SelectedDashboard.Widgets.Add(widgetGeneratorToAdd.CreateWidget()); + SelectedWorkflow.Widgets.Add(widgetGeneratorToAdd.CreateWidget()); EditMode = true; }); [RelayCommand] public void AddWidget(WidgetGenerator generator) { - SelectedDashboard.Widgets.Add(generator.CreateWidget()); + SelectedWorkflow.Widgets.Add(generator.CreateWidget()); + } + + [RelayCommand] + public void AddWorkflow() + { + SelectedProject.AddWorkflow(); } [RelayCommand] @@ -143,13 +181,6 @@ public void ToggleEditDashboard() /// The command done configuring widget. //public ICommand CommandDoneConfiguringWidget => new RelayCommand(() => ConfiguringWidget = null); - /// - /// Gets the command edit dashboard. - /// - /// The command edit dashboard. - //public ICommand CommandEditDashboard => new RelayCommand(o => EditMode = o.ToString() == "True", o => ConfiguringWidget == null); - public ICommand CommandEditDashboard => new RelayCommand(o => EditMode = o.ToString() == "True", o => true); - ///// ///// Gets the command manage dashboard. ///// @@ -166,12 +197,6 @@ public void ToggleEditDashboard() //public ICommand CommandNewDashboard => new RelayCommand(() => // ConfiguringDashboard = new DashboardSettingsPromptViewModel(DashboardConfigurationType.New, this)); - /// - /// Gets the command remove widget. - /// - /// The command remove widget. - public ICommand CommandRemoveWidget => new RelayCommand(o => SelectedDashboard.Widgets.Remove((WidgetContext)o)); - #endregion Public Properties #region Public Methods @@ -184,22 +209,20 @@ public void ToggleEditDashboard() /// The new name. public void DashboardConfigurationComplete(DashboardConfigurationType type, bool save, string newName) { - //ConfiguringDashboard = null; - - if (!save) - return; - - switch (type) - { - case DashboardConfigurationType.New: - var dashboardModel = new WorkflowContext { Title = newName }; - Dashboards.Add(dashboardModel); - SelectedDashboard = dashboardModel; - return; - case DashboardConfigurationType.Existing: - SelectedDashboard.Title = newName; - return; - } + //if (!save) + // return; + + //switch (type) + //{ + // case DashboardConfigurationType.New: + // var dashboardModel = new WorkflowContext { Title = newName }; + // Workflows.Add(dashboardModel); + // SelectedWorkflow = dashboardModel; + // return; + // case DashboardConfigurationType.Existing: + // SelectedWorkflow.Title = newName; + // return; + //} } /// @@ -209,7 +232,7 @@ public void DashboardConfigurationComplete(DashboardConfigurationType type, bool /// DashboardNameValidResponse. public DashboardNameValidResponse DashboardNameValid(string name) { - return Dashboards.Any(dashboard => dashboard.Title == name) + return Workflows.Any(dashboard => dashboard.Title == name) ? new DashboardNameValidResponse(false, $"That Dashboard Name [{name}] already exists.") : new DashboardNameValidResponse(true); } @@ -223,7 +246,6 @@ public Task Start(IServiceProvider services) // -------------------------------------------------------------------------- // Available Widgets // -------------------------------------------------------------------------- - IPackageService widgetService = services.GetService(); // -------------------------------------------------------------------------- // Load Component Data @@ -232,8 +254,11 @@ public Task Start(IServiceProvider services) { new ProjectContext { Title = "My Project" } }; - Dashboards = [new WorkflowContext { Title = "My Workflow" }]; - SelectedDashboard = Dashboards[0]; + SelectedProject = Projects[0]; + SelectedProject.Workflows.Add(new WorkflowContext { Title = "My Workflow" }); + + //Workflows = [new WorkflowContext { Title = "My Workflow" }]; + //SelectedWorkflow = Workflows[0]; AddWidgetMenuItemViewModels = new ObservableCollection(); // -------------------------------------------------------------------------- @@ -245,7 +270,8 @@ public Task Start(IServiceProvider services) MenuItems = new ObservableCollection(), }); - foreach (var widget in widgetService.GetAvailableWidgets()) + IPackageService packageService = services.GetService(); + foreach (var widget in packageService.GetAvailableWidgets()) { var fullMenuHeader = widget.MenuPath; if (string.IsNullOrEmpty(fullMenuHeader)) @@ -266,7 +292,7 @@ public Task Start(IServiceProvider services) Header = splitedMenuHeaders[i], Command = new RelayCommand(() => { - SelectedDashboard.Widgets.Add(widget.CreateWidget()); + SelectedProject.SelectedWorkflow.Widgets.Add(widget.CreateWidget()); }, () => true), }); } diff --git a/src/Apps/Corathing.Organizer/ViewModels/OrganizerSettingsViewModel.cs b/src/Apps/Corathing.Organizer/ViewModels/OrganizerSettingsViewModel.cs index 4e5a0d1..aeb7c61 100644 --- a/src/Apps/Corathing.Organizer/ViewModels/OrganizerSettingsViewModel.cs +++ b/src/Apps/Corathing.Organizer/ViewModels/OrganizerSettingsViewModel.cs @@ -10,15 +10,22 @@ using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; +using Corathing.Contracts.Bases; using Corathing.Contracts.Services; +using Corathing.Dashboards.WPF.Services; +using Corathing.Organizer.Services; namespace Corathing.Organizer.ViewModels; public partial class OrganizerSettingsViewModel : ObservableRecipient { + #region Readonly Properties in Initializing private readonly IThemeService _themeService; + private readonly ILocalizationService _localizationService; + private readonly IAppStateService _appStateService; private bool _isInitialized = false; + #endregion [ObservableProperty] private string _appVersion = string.Empty; @@ -26,9 +33,26 @@ public partial class OrganizerSettingsViewModel : ObservableRecipient [ObservableProperty] private ApplicationTheme _currentApplicationTheme = ApplicationTheme.Unknown; - public OrganizerSettingsViewModel(IThemeService themeService) + [ObservableProperty] + private ApplicationLanguage _currentApplicationLanguage = ApplicationLanguage.Unknown; + + [ObservableProperty] + private bool? _useGlobalConfiguration; + + [ObservableProperty] + private bool? _useAppPathConfiguration; + + [ObservableProperty] + private string _customPath; + + public OrganizerSettingsViewModel( + IThemeService themeService, + ILocalizationService localizationService, + IAppStateService appStateService) { _themeService = themeService; + _localizationService = localizationService; + _appStateService = appStateService; InitializeViewModel(); } @@ -48,21 +72,53 @@ partial void OnCurrentApplicationThemeChanged(ApplicationTheme oldValue, Applica _themeService.Apply(newValue); } + partial void OnCurrentApplicationLanguageChanged(ApplicationLanguage oldValue, ApplicationLanguage newValue) + { + _localizationService.Apply(newValue); + } + + partial void OnUseGlobalConfigurationChanged(bool? oldValue, bool? newValue) + { + var appSettings = _appStateService.GetAppSettings(); + if (appSettings.UseGlobalConfiguration == newValue) + return; + appSettings.UseGlobalConfiguration = newValue; + _appStateService.UpdateAppSettings(appSettings); + } + + partial void OnUseAppPathConfigurationChanged(bool? oldValue, bool? newValue) + { + var appSettings = _appStateService.GetAppSettings(); + if (appSettings.UseAppPathConfiguration == newValue) + return; + appSettings.UseAppPathConfiguration = newValue; + _appStateService.UpdateAppSettings(appSettings); + } + + partial void OnCustomPathChanged(string? oldValue, string newValue) + { + var appSettings = _appStateService.GetAppSettings(); + // FIXME: + // / \ 차이와 Lower Trim 등을 적용하여야함 + if (string.Compare(appSettings.CustomPath, newValue) == 0) + return; + appSettings.CustomPath = newValue; + _appStateService.UpdateAppSettings(appSettings); + } + + private void InitializeViewModel() { CurrentApplicationTheme = _themeService.GetAppTheme(); + CurrentApplicationLanguage = _localizationService.GetAppLanguage(); AppVersion = $"{GetAssemblyVersion()}"; - _isInitialized = true; - } + var appSettings = _appStateService.GetAppSettings(); + UseGlobalConfiguration = appSettings.UseGlobalConfiguration; + UseAppPathConfiguration = appSettings.UseAppPathConfiguration; + CustomPath = appSettings.CustomPath; - private void OnThemeChanged(ApplicationTheme currentApplicationTheme, Color systemAccent) - { - // Update the theme if it has been changed elsewhere than in the settings. - if (CurrentApplicationTheme != currentApplicationTheme) - { - CurrentApplicationTheme = currentApplicationTheme; - } + _isInitialized = true; } [RelayCommand] diff --git a/src/Apps/Corathing.Organizer/ViewModels/ProjectSettingsViewModel.cs b/src/Apps/Corathing.Organizer/ViewModels/ProjectSettingsViewModel.cs new file mode 100644 index 0000000..81c95af --- /dev/null +++ b/src/Apps/Corathing.Organizer/ViewModels/ProjectSettingsViewModel.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; + +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; + +namespace Corathing.Organizer.ViewModels; + +public partial class ProjectSettingsViewModel : ObservableObject +{ + public ProjectSettingsViewModel(IServiceProvider services) + { + + } + + [RelayCommand] + public void Close(Window window) + { + window.Close(); + } + +} diff --git a/src/Apps/Corathing.Organizer/ViewModels/WidgetSettingsViewModel.cs b/src/Apps/Corathing.Organizer/ViewModels/WidgetSettingsViewModel.cs index c44d13c..9a293f8 100644 --- a/src/Apps/Corathing.Organizer/ViewModels/WidgetSettingsViewModel.cs +++ b/src/Apps/Corathing.Organizer/ViewModels/WidgetSettingsViewModel.cs @@ -3,11 +3,22 @@ using System.Linq; using System.Text; using System.Threading.Tasks; +using System.Windows; using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; namespace Corathing.Organizer.ViewModels; -public class WidgetSettingsViewModel : ObservableObject +public partial class WidgetSettingsViewModel : ObservableObject { + public WidgetSettingsViewModel(IServiceProvider services) + { + + } + [RelayCommand] + public void Close(Window window) + { + window.Close(); + } } diff --git a/src/Apps/Corathing.Organizer/Views/DashboardView.xaml b/src/Apps/Corathing.Organizer/Views/DashboardView.xaml index a4bba74..b110e52 100644 --- a/src/Apps/Corathing.Organizer/Views/DashboardView.xaml +++ b/src/Apps/Corathing.Organizer/Views/DashboardView.xaml @@ -4,11 +4,13 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:Corathing.Organizer.Views" + xmlns:models="clr-namespace:Corathing.Organizer.Models" xmlns:viewmodels="clr-namespace:Corathing.Organizer.ViewModels" xmlns:converters="clr-namespace:Corathing.Dashboards.WPF.Converters;assembly=Corathing.Dashboards.WPF" xmlns:dashboardControl="clr-namespace:Corathing.Dashboards.WPF.Controls;assembly=Corathing.Dashboards.WPF" xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml" + xmlns:behavior="clr-namespace:Corathing.Organizer.Behaviors" mc:Ignorable="d" Background="{DynamicResource ApplicationBackgroundBrush}" Foreground="{DynamicResource TextFillColorPrimaryBrush}" @@ -16,11 +18,48 @@ d:DesignWidth="1600"> + + + + + + + + + + + + + + + + + + + + + + + + + @@ -51,11 +90,16 @@ - + + + + + @@ -118,20 +162,16 @@ Style="{DynamicResource DashboardSelectorToggle}" />--> - + - + @@ -225,21 +262,11 @@ - - + Style="{StaticResource IconButton24}" + Margin="0,0,10,0" + Icon="{ui:SymbolIcon Settings24}" + Command="{Binding OpenOrganizerSettingsCommand}" + ToolTip="Open settings dashboard" /> @@ -261,13 +288,92 @@ Icon="Home24" /> - - + + + + + + + + + + + + + + + + diff --git a/src/Apps/Corathing.Organizer/Views/DashboardView.xaml.cs b/src/Apps/Corathing.Organizer/Views/DashboardView.xaml.cs index d922d36..f6388a8 100644 --- a/src/Apps/Corathing.Organizer/Views/DashboardView.xaml.cs +++ b/src/Apps/Corathing.Organizer/Views/DashboardView.xaml.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.ComponentModel; using System.Linq; +using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; using System.Windows; @@ -103,22 +105,70 @@ public DashboardView() DataContext = ViewModel = new DashboardsViewModel() { EditMode = false }; + //DashboardHostTabControl.SelectionChanged += DashboardHostTabControl_SelectionChanged; + Loaded += (s, e) => { - IAuthService authService = App.Current.Services.GetService(); - if (authService != null && authService.UseAuthService) + ViewModel.Start(App.Current.Services); + }; + } + + private void DashboardHostTabControl_SelectionChanged(object sender, SelectionChangedEventArgs e) + { + if (e.Source is TabControl) + { + var pos = DashboardHostTabControl.SelectedIndex; + if (pos != 0 && pos == ViewModel.SelectedProject.Workflows.Count - 1) //last tab { - //var loginWindow = new BaseWindow(); - //loginWindow.Content = new LoginView(); - //loginWindow.Owner = Window.GetWindow(this); - //loginWindow.ShowDialog(); - //if (loginWindow.DialogResult == false) - //{ - // // System.Shutdown - //} + var tab = ViewModel.SelectedProject.Workflows.Last(); + ConvertPlusToNewTab(tab); + AddNewPlusButton(); } + } + } - ViewModel.Start(App.Current.Services); + void ConvertPlusToNewTab(WorkflowContext tab) + { + //Do things to make it a new tab. + TabIndex++; + tab.Title = $"Tab {TabIndex}"; + tab.IsPlaceholder = false; + //tab.Content = new ContentVM("Tab content", TabIndex); + } + + void AddNewPlusButton() + { + var plusTab = new WorkflowContext() + { + Title = "+", + IsPlaceholder = true }; + ViewModel.SelectedProject.Workflows.Add(plusTab); + } + + + class ContentVM + { + public ContentVM(string name, int index) + { + Name = name; + Index = index; + } + public string Name { get; set; } + public int Index { get; set; } + } + + private void OnTabCloseClick(object sender, RoutedEventArgs e) + { + var tab = (sender as Button).DataContext as WorkflowContext; + if (ViewModel.SelectedProject.Workflows.Count > 2) + { + var index = ViewModel.SelectedProject.Workflows.IndexOf(tab); + if (index == ViewModel.SelectedProject.Workflows.Count - 2)//last tab before [+] + { + DashboardHostTabControl.SelectedIndex--; + } + ViewModel.SelectedProject.Workflows.RemoveAt(index); + } } } diff --git a/src/Apps/Corathing.Organizer/Views/OrganizerSettingsView.xaml b/src/Apps/Corathing.Organizer/Views/OrganizerSettingsView.xaml index 77e267c..2506fdd 100644 --- a/src/Apps/Corathing.Organizer/Views/OrganizerSettingsView.xaml +++ b/src/Apps/Corathing.Organizer/Views/OrganizerSettingsView.xaml @@ -7,15 +7,22 @@ xmlns:viewmodels="clr-namespace:Corathing.Organizer.ViewModels" xmlns:converters="clr-namespace:Corathing.Organizer.Converters" xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml" + xmlns:localizations="clr-namespace:Corathing.Dashboards.WPF.Bindings;assembly=Corathing.Dashboards.WPF" mc:Ignorable="d" Background="{DynamicResource ApplicationBackgroundBrush}" Foreground="{DynamicResource TextFillColorPrimaryBrush}" d:DataContext="{d:DesignInstance viewmodels:OrganizerSettingsViewModel, IsDesignTimeCreatable=False}" - Margin="24" + Margin="16" Title="OrganizerSettingsView"> - + + + + + + + @@ -35,17 +42,17 @@ - + Text="{localizations:Localization Corathing.Organizer.Settings}" /> + - + Text="{localizations:Localization Corathing.Organizer.ManageCorathingAppConfigurationFile}" /> @@ -61,11 +68,11 @@ + Text="{localizations:Localization Corathing.Organizer.CurrentConfigureFile}" /> + Text="{localizations:Localization Corathing.Organizer.CurrentConfigureFileDescription}" /> - - - - - - - - + + CornerRadius="0"> + + + + - - + + + + + BorderThickness="0,1,0,0" + CornerRadius="0"> + + + + - - + + + + + + + + + + + + + + + + + + + - @@ -134,6 +184,7 @@ + @@ -144,20 +195,21 @@ + Text="{localizations:Localization Corathing.Organizer.AppTheme}" /> + Text="{localizations:Localization Corathing.Organizer.AppThemeDescription}" /> - - + + - + + @@ -168,20 +220,106 @@ + Text="{localizations:Localization Corathing.Organizer.AppLanguage}" /> + Text="{localizations:Localization Corathing.Organizer.AppLanguageDescription}" /> - - + SelectedIndex="{Binding CurrentApplicationLanguage, Converter={StaticResource ApplicationLanguageToIndexConverter}, Mode=TwoWay}"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Apps/Corathing.Organizer/Views/OrganizerSettingsView.xaml.cs b/src/Apps/Corathing.Organizer/Views/OrganizerSettingsView.xaml.cs index 0d55362..ff242d0 100644 --- a/src/Apps/Corathing.Organizer/Views/OrganizerSettingsView.xaml.cs +++ b/src/Apps/Corathing.Organizer/Views/OrganizerSettingsView.xaml.cs @@ -13,6 +13,7 @@ using System.Windows.Navigation; using System.Windows.Shapes; +using Corathing.Organizer.Extensions; using Corathing.Organizer.ViewModels; using Microsoft.Extensions.DependencyInjection; @@ -31,6 +32,13 @@ public OrganizerSettingsView() InitializeComponent(); DataContext = ViewModel = App.Current.Services.GetService(); + + Loaded += (s, e) => + { + var window = Window.GetWindow(this); + window.Width = 800; + window.CenterWindowToParent(); + }; } } } diff --git a/src/Apps/Corathing.Organizer/Views/ProjectSettingsView.xaml b/src/Apps/Corathing.Organizer/Views/ProjectSettingsView.xaml index 0037c5b..24f0f92 100644 --- a/src/Apps/Corathing.Organizer/Views/ProjectSettingsView.xaml +++ b/src/Apps/Corathing.Organizer/Views/ProjectSettingsView.xaml @@ -2,13 +2,41 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:Corathing.Organizer.Views" - mc:Ignorable="d" - d:DesignHeight="450" d:DesignWidth="800" + xmlns:viewmodels="clr-namespace:Corathing.Organizer.ViewModels" + xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml" + mc:Ignorable="d" + Background="Transparent" + Margin="16" Title="ProjectSettingsView"> - - - + + + + + + + + + + + + + + + diff --git a/src/Apps/Corathing.Organizer/Views/ProjectSettingsView.xaml.cs b/src/Apps/Corathing.Organizer/Views/ProjectSettingsView.xaml.cs index b997270..d7a2c02 100644 --- a/src/Apps/Corathing.Organizer/Views/ProjectSettingsView.xaml.cs +++ b/src/Apps/Corathing.Organizer/Views/ProjectSettingsView.xaml.cs @@ -13,6 +13,10 @@ using System.Windows.Navigation; using System.Windows.Shapes; +using Corathing.Organizer.Extensions; +using Corathing.Organizer.ViewModels; +using Microsoft.Extensions.DependencyInjection; + namespace Corathing.Organizer.Views { /// @@ -20,9 +24,20 @@ namespace Corathing.Organizer.Views /// public partial class ProjectSettingsView : Page { + public ProjectSettingsViewModel? ViewModel; + public ProjectSettingsView() { InitializeComponent(); + + DataContext = ViewModel = App.Current.Services.GetService(); + + Loaded += (s, e) => + { + var window = Window.GetWindow(this); + window.Width = 1000; + window.CenterWindowToParent(); + }; } } } diff --git a/src/Apps/Corathing.Organizer/Views/WidgetSettingsView.xaml b/src/Apps/Corathing.Organizer/Views/WidgetSettingsView.xaml index 27b8d96..7edd92e 100644 --- a/src/Apps/Corathing.Organizer/Views/WidgetSettingsView.xaml +++ b/src/Apps/Corathing.Organizer/Views/WidgetSettingsView.xaml @@ -4,142 +4,40 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:Corathing.Organizer.Views" + xmlns:viewmodels="clr-namespace:Corathing.Organizer.ViewModels" xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml" - mc:Ignorable="d" - d:DesignHeight="450" d:DesignWidth="800" + mc:Ignorable="d" + d:DesignHeight="450" + d:DesignWidth="800" + Margin="16" Title="WidgetSettingsView"> - - - - - - - - - - - - - - - - - - - + + + + + + + + - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - + + diff --git a/src/Apps/Corathing.Organizer/Views/WidgetSettingsView.xaml.cs b/src/Apps/Corathing.Organizer/Views/WidgetSettingsView.xaml.cs index c49a65b..5b67bfa 100644 --- a/src/Apps/Corathing.Organizer/Views/WidgetSettingsView.xaml.cs +++ b/src/Apps/Corathing.Organizer/Views/WidgetSettingsView.xaml.cs @@ -14,6 +14,10 @@ using System.Windows.Shapes; using Corathing.Dashboards.WPF.Controls; +using Corathing.Organizer.Extensions; +using Corathing.Organizer.ViewModels; + +using Microsoft.Extensions.DependencyInjection; namespace Corathing.Organizer.Views { @@ -22,9 +26,20 @@ namespace Corathing.Organizer.Views /// public partial class WidgetSettingsView : Page { + public WidgetSettingsViewModel ViewModel { get; set; } + public WidgetSettingsView(WidgetHost widgetHost) { InitializeComponent(); + + DataContext = ViewModel = App.Current.Services.GetService(); + + Loaded += (s, e) => + { + var window = Window.GetWindow(this); + window.Width = 1000; + window.CenterWindowToParent(); + }; } } } diff --git a/src/Apps/Corathing.Organizer/appsettings.json b/src/Apps/Corathing.Organizer/appsettings.json new file mode 100644 index 0000000..b8f7c90 --- /dev/null +++ b/src/Apps/Corathing.Organizer/appsettings.json @@ -0,0 +1,17 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + }, + "AllowedHosts": "*", + "Corathing": { + "Organizer": { + "UseGlobalConfiguration": false, + "UseAppPathConfiguration": true, + "CustomPath": "" + } + } +} \ No newline at end of file diff --git a/src/Shared/Corathing.Contracts/Bases/AppSettings.cs b/src/Shared/Corathing.Contracts/Bases/AppSettings.cs new file mode 100644 index 0000000..23bc838 --- /dev/null +++ b/src/Shared/Corathing.Contracts/Bases/AppSettings.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Corathing.Contracts.Bases; + +public class AppSettings +{ + public bool? UseGlobalConfiguration { get; set; } + public bool? UseAppPathConfiguration { get; set; } + public string? CustomPath { get; set; } +} diff --git a/src/Shared/Corathing.Contracts/Bases/AppState.cs b/src/Shared/Corathing.Contracts/Bases/AppState.cs new file mode 100644 index 0000000..d4124f6 --- /dev/null +++ b/src/Shared/Corathing.Contracts/Bases/AppState.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Corathing.Contracts.Bases; + +public class AppState +{ +} diff --git a/src/Shared/Corathing.Contracts/Factories/AppSettingsFactory.cs b/src/Shared/Corathing.Contracts/Factories/AppSettingsFactory.cs new file mode 100644 index 0000000..f4ae469 --- /dev/null +++ b/src/Shared/Corathing.Contracts/Factories/AppSettingsFactory.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using Corathing.Contracts.Bases; + +namespace Corathing.Contracts.Factories; + +public static class AppSettingsFactory +{ + public static AppSettings Create() + => new AppSettings() + { + UseGlobalConfiguration = false, + UseAppPathConfiguration = true, + CustomPath = "", + }; + + public static AppSettings Copy(this AppSettings appSettings) + => new AppSettings() + { + UseGlobalConfiguration = appSettings.UseGlobalConfiguration, + UseAppPathConfiguration = appSettings.UseAppPathConfiguration, + CustomPath = appSettings.CustomPath, + }; + + public static AppSettings CopyWithUpdate( + this AppSettings appSettings, + bool? useGlobalConfiguration = null, + bool? useAppPathConfiguration = null, + string? customPath = null) + => new AppSettings() + { + UseGlobalConfiguration = useGlobalConfiguration ?? appSettings.UseGlobalConfiguration, + UseAppPathConfiguration = useAppPathConfiguration ?? appSettings.UseAppPathConfiguration, + CustomPath = customPath ?? appSettings.CustomPath, + }; +} diff --git a/src/Shared/Corathing.Contracts/Factories/AppStateFactory.cs b/src/Shared/Corathing.Contracts/Factories/AppStateFactory.cs new file mode 100644 index 0000000..7bff9e5 --- /dev/null +++ b/src/Shared/Corathing.Contracts/Factories/AppStateFactory.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using Corathing.Contracts.Bases; + +namespace Corathing.Contracts.Factories; + +public static class AppStateFactory +{ + public static AppState Create() + => new AppState() + { + + }; +} diff --git a/src/Shared/Corathing.Contracts/Services/IAppStateService.cs b/src/Shared/Corathing.Contracts/Services/IAppStateService.cs index c885ef5..364ce18 100644 --- a/src/Shared/Corathing.Contracts/Services/IAppStateService.cs +++ b/src/Shared/Corathing.Contracts/Services/IAppStateService.cs @@ -10,7 +10,9 @@ namespace Corathing.Contracts.Services; public interface IAppStateService { - void Update(string key, string value); + AppSettings GetAppSettings(); + void UpdateAppSettings(AppSettings appSettings); + void UpdateOverwrite(Guid id, object value); void UpdateOrAdd(Guid id, object value); bool TryGetWorkflow(Guid id, out WorkflowState workflow); diff --git a/src/Shared/Corathing.Contracts/Services/ILocalizationService.cs b/src/Shared/Corathing.Contracts/Services/ILocalizationService.cs new file mode 100644 index 0000000..98aa1d2 --- /dev/null +++ b/src/Shared/Corathing.Contracts/Services/ILocalizationService.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Resources; + +namespace Corathing.Contracts.Services; + +public enum ApplicationLanguage +{ + Unknown, + ko_KR, + en_US, +} + +public interface ILocalizationService +{ + void RegisterStringResourceManager(string namespaceName, ResourceManager resourceManager); + + void Apply(ApplicationLanguage language); + void ApplySystemLanguage(); + ApplicationLanguage GetAppLanguage(); + CultureInfo GetAppCulture(); + CultureInfo GetSystemCulture(); +} diff --git a/src/Shared/Corathing.Dashboards.WPF/Bindings/LocalizationExtension.cs b/src/Shared/Corathing.Dashboards.WPF/Bindings/LocalizationExtension.cs new file mode 100644 index 0000000..8ed0f30 --- /dev/null +++ b/src/Shared/Corathing.Dashboards.WPF/Bindings/LocalizationExtension.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Globalization; +using System.Linq; +using System.Resources; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Data; + +using Corathing.Dashboards.WPF.Services; + +namespace Corathing.Dashboards.WPF.Bindings; + +public class LocalizationExtension : Binding +{ + public LocalizationExtension(string name) : base("[" + name + "]") + { + Mode = BindingMode.OneWay; + Source = LocalizationService.Instance; + } +} diff --git a/src/Shared/Corathing.Dashboards.WPF/Bindings/Localizer.cs b/src/Shared/Corathing.Dashboards.WPF/Bindings/Localizer.cs deleted file mode 100644 index f225a36..0000000 --- a/src/Shared/Corathing.Dashboards.WPF/Bindings/Localizer.cs +++ /dev/null @@ -1,152 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Globalization; -using System.Linq; -using System.Resources; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Data; - -namespace Corathing.Dashboards.WPF.Bindings; - -public enum AvailableCulture -{ - en_US, - ko_KR -} - -public class LocalizationOptions -{ - public const string Section = "Corathing:Preferences:Localization"; - - /// - /// The culture to use for localization. - /// - [DefaultValue(AvailableCulture.ko_KR)] - public AvailableCulture Culture { get; set; } - - /// - /// The relative path under application root where resource files are located. - /// - public string ResourcesPath { get; set; } = string.Empty; -} - -public class Localizer : INotifyPropertyChanged -{ - #region 1. 싱글톤 - private new static readonly Localizer _instance = new Localizer(); - public static Localizer Instance => _instance; - #endregion - - public Localizer() - { - CurrentCulture = CultureInfo.CurrentCulture; - } - - //public static void Configure(IConfigurationRoot configuration) - //{ - // configuration - // .GetSection(LocalizationOptions.Section) - // .Bind(Instance._localizationOptions); - //} - - public const string LocalizationChangedEventMessage = "LocalizationChangeEventMessage"; - - private readonly Dictionary _stringResourceManagers = new Dictionary(); - private readonly Dictionary _assetResourceManagers = new Dictionary(); - private CultureInfo? currentCulture = null; - - public string? this[string key] - { - get - { - foreach (var resManager in _stringResourceManagers.Values) - { - string? resultString = resManager.GetString(key, currentCulture); - if (!string.IsNullOrEmpty(resultString)) - { - return resultString; - } - } - return ""; - } - } - - public CultureInfo? CurrentCulture - { - get { return currentCulture; } - set - { - if (currentCulture != value) - { - currentCulture = value; - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(null)); - } - } - } - - public event PropertyChangedEventHandler? PropertyChanged; - - public void AddStringResourceManager(string baseName, Type type) - { - _stringResourceManagers[baseName] = new ResourceManager(type); - } - - public void AddAssetResourceManager(string baseName, Type type) - { - _assetResourceManagers[baseName] = new ResourceManager(type); - } - - public static string ConvertCultureName(AvailableCulture culture) - => culture switch - { - AvailableCulture.en_US => "en-US", - AvailableCulture.ko_KR => "ko-KR", - _ => "ko-KR", // fallback to Korean - }; - - public static void SetCulture(AvailableCulture culture) - => SetCulture(CultureInfo.GetCultureInfo(ConvertCultureName(culture))); - - public static void SetCulture(CultureInfo? culture) - { - CultureInfo.DefaultThreadCurrentCulture = culture; - CultureInfo.DefaultThreadCurrentUICulture = culture; - Instance.CurrentCulture = culture; - } - - public static AvailableCulture SetNextAvailableCulture() - { - AvailableCulture nextCulture = GetNextAvailableCulture(); - SetCulture(nextCulture); - return nextCulture; - } - - public static AvailableCulture GetNextAvailableCulture() - { - if (Instance.CurrentCulture == null) - { - return AvailableCulture.ko_KR; - } - switch (Instance.CurrentCulture.Name) - { - case "en-US": - return AvailableCulture.ko_KR; - case "ko-KR": - return AvailableCulture.en_US; - default: - return AvailableCulture.ko_KR; - } - } - -} - -public class LocalizationExtension : Binding -{ - public LocalizationExtension(string name) : base("[" + name + "]") - { - Mode = BindingMode.OneWay; - Source = Localizer.Instance; - } -} diff --git a/src/Shared/Corathing.Dashboards.WPF/Controls/DashboardHost.xaml.cs b/src/Shared/Corathing.Dashboards.WPF/Controls/DashboardHost.xaml.cs index 5381f7f..57a0469 100644 --- a/src/Shared/Corathing.Dashboards.WPF/Controls/DashboardHost.xaml.cs +++ b/src/Shared/Corathing.Dashboards.WPF/Controls/DashboardHost.xaml.cs @@ -60,7 +60,7 @@ public bool EnableColumnLimit nameof(MaxNumColumns), typeof(int), typeof(DashboardHost), - new PropertyMetadata(16)); + new PropertyMetadata(32)); /// /// The number property diff --git a/src/Shared/Corathing.Dashboards.WPF/Controls/WidgetHost.xaml b/src/Shared/Corathing.Dashboards.WPF/Controls/WidgetHost.xaml index 95809e4..5d02fdb 100644 --- a/src/Shared/Corathing.Dashboards.WPF/Controls/WidgetHost.xaml +++ b/src/Shared/Corathing.Dashboards.WPF/Controls/WidgetHost.xaml @@ -122,7 +122,7 @@ - -