diff --git a/src/PTRP.App/App.xaml.cs b/src/PTRP.App/App.xaml.cs index 41252e2..df8423d 100644 --- a/src/PTRP.App/App.xaml.cs +++ b/src/PTRP.App/App.xaml.cs @@ -3,17 +3,21 @@ using PTRP.Services; using PTRP.Services.Interfaces; using PTRP.ViewModels; +using PTRP.ViewModels.Calendar; using PTRP.ViewModels.Educators; using PTRP.ViewModels.Patients; using PTRP.ViewModels.Projects; +using PTRP.ViewModels.Visits; using PTRP.Data; using PTRP.Data.Repositories; using PTRP.Data.Repositories.Interfaces; using PTRP.App.Infrastructure; +using PTRP.App.Views.Calendar; using PTRP.App.Views.Patients; using PTRP.App.Views.Educators; using PTRP.App.Views.Projects; using PTRP.App.Views.Sync; +using PTRP.App.Views.Visits; using System.IO; using System.Windows; @@ -127,6 +131,8 @@ private void ConfigureServices(ServiceCollection services) services.AddTransient(); // Issue #63: Educator List ViewModel services.AddTransient(); // Issue #64: Project List ViewModel services.AddTransient(); // Issue #74: Project Form ViewModel + services.AddTransient(); // Issue #75: Calendar ViewModel + services.AddTransient(); // Issue #75: Visit Form ViewModel services.AddTransient(); // Issue #52: Sync ViewModel services.AddTransient(); // Issue #52: Conflict Resolution ViewModel @@ -135,6 +141,8 @@ private void ConfigureServices(ServiceCollection services) services.AddScoped(); // Issue #51/#74: Patient List View services.AddScoped(); // Issue #63: Educator List View services.AddScoped(); // Issue #64: Project List View + services.AddScoped(); // Issue #75: Calendar View + services.AddScoped(); // Issue #75: Visit Form View services.AddScoped(); // Issue #52: Sync View } diff --git a/src/PTRP.App/Converters/BoolToColorConverter.cs b/src/PTRP.App/Converters/BoolToColorConverter.cs new file mode 100644 index 0000000..8a1d343 --- /dev/null +++ b/src/PTRP.App/Converters/BoolToColorConverter.cs @@ -0,0 +1,41 @@ +using System; +using System.Globalization; +using System.Windows.Data; +using System.Windows.Media; + +namespace PTRP.App.Converters; + +/// +/// Converte un booleano in un colore basato su parametro "TrueColor|FalseColor" +/// Esempio: "#007ACC|Transparent" => True = #007ACC, False = Transparent +/// +public class BoolToColorConverter : IValueConverter +{ + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value is not bool boolValue) + return Brushes.Transparent; + + var param = parameter?.ToString() ?? "Black|Gray"; + var colors = param.Split('|'); + + if (colors.Length != 2) + return Brushes.Transparent; + + var targetColor = boolValue ? colors[0] : colors[1]; + + try + { + return (Brush)new BrushConverter().ConvertFromString(targetColor)!; + } + catch + { + return Brushes.Transparent; + } + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } +} diff --git a/src/PTRP.App/Converters/BoolToFontWeightConverter.cs b/src/PTRP.App/Converters/BoolToFontWeightConverter.cs new file mode 100644 index 0000000..52a1586 --- /dev/null +++ b/src/PTRP.App/Converters/BoolToFontWeightConverter.cs @@ -0,0 +1,25 @@ +using System; +using System.Globalization; +using System.Windows; +using System.Windows.Data; + +namespace PTRP.App.Converters; + +/// +/// Converte un booleano in FontWeight (Bold se True, Normal se False) +/// +public class BoolToFontWeightConverter : IValueConverter +{ + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value is bool boolValue && boolValue) + return FontWeights.Bold; + + return FontWeights.Normal; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } +} diff --git a/src/PTRP.App/Converters/InverseBooleanToVisibilityConverter.cs b/src/PTRP.App/Converters/InverseBooleanToVisibilityConverter.cs new file mode 100644 index 0000000..cb4a1a4 --- /dev/null +++ b/src/PTRP.App/Converters/InverseBooleanToVisibilityConverter.cs @@ -0,0 +1,28 @@ +using System; +using System.Globalization; +using System.Windows; +using System.Windows.Data; + +namespace PTRP.App.Converters; + +/// +/// Converte un booleano in Visibility (inverso: False = Visible, True = Collapsed) +/// +public class InverseBooleanToVisibilityConverter : IValueConverter +{ + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value is bool boolValue) + return boolValue ? Visibility.Collapsed : Visibility.Visible; + + return Visibility.Collapsed; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value is Visibility visibility) + return visibility != Visibility.Visible; + + return false; + } +} diff --git a/src/PTRP.App/Infrastructure/ViewLocator.cs b/src/PTRP.App/Infrastructure/ViewLocator.cs index 3483f16..fc8314e 100644 --- a/src/PTRP.App/Infrastructure/ViewLocator.cs +++ b/src/PTRP.App/Infrastructure/ViewLocator.cs @@ -1,12 +1,14 @@ using System; using System.Windows.Controls; using Microsoft.Extensions.DependencyInjection; +using PTRP.App.Views.Calendar; using PTRP.App.Views.Educators; using PTRP.App.Views.Patients; using PTRP.App.Views.Projects; using PTRP.App.Views.Setup; using PTRP.App.Views.Sync; using PTRP.ViewModels; +using PTRP.ViewModels.Calendar; using PTRP.ViewModels.Educators; using PTRP.ViewModels.Patients; using PTRP.ViewModels.Projects; @@ -56,6 +58,9 @@ public ViewLocator(IServiceProvider serviceProvider) // so it's not navigated to directly - it's opened in dialogs ProjectFormViewModel => new ProjectFormView(), + // Calendar Module (Issue #75) + CalendarViewModel => _serviceProvider.GetRequiredService(), + // Sync Module (requires IServiceProvider in constructor) SyncViewModel => _serviceProvider.GetRequiredService(), diff --git a/src/PTRP.App/Views/Calendar/CalendarView.xaml b/src/PTRP.App/Views/Calendar/CalendarView.xaml new file mode 100644 index 0000000..3402410 --- /dev/null +++ b/src/PTRP.App/Views/Calendar/CalendarView.xaml @@ -0,0 +1,310 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +