Calendar stuff.

This commit is contained in:
Burak Kaan Köse
2026-02-13 03:09:13 +01:00
parent e936c431a2
commit 884f000058
22 changed files with 470 additions and 115 deletions
@@ -99,6 +99,7 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel,
{ {
Messenger.Send(new CalendarDisplayTypeChangedMessage(StatePersistenceService.CalendarDisplayType)); Messenger.Send(new CalendarDisplayTypeChangedMessage(StatePersistenceService.CalendarDisplayType));
UpdateDateNavigationHeaderItems();
// Change the calendar. // Change the calendar.
DateClicked(new CalendarViewDayClickedEventArgs(GetDisplayTypeSwitchDate())); DateClicked(new CalendarViewDayClickedEventArgs(GetDisplayTypeSwitchDate()));
@@ -253,8 +254,6 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel,
break; break;
case CalendarDisplayType.Month: case CalendarDisplayType.Month:
break; break;
case CalendarDisplayType.Year:
break;
default: default:
break; break;
} }
@@ -320,49 +319,88 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel,
/// </summary> /// </summary>
private void UpdateDateNavigationHeaderItems() private void UpdateDateNavigationHeaderItems()
{ {
DateNavigationHeaderItems.Clear(); var settings = PreferencesService.GetCurrentCalendarSettings();
var cultureInfo = settings.CultureInfo ?? CultureInfo.CurrentUICulture;
// TODO: From settings var visibleRange = HighlightedDateRange ?? new DateRange(DateTime.Today, DateTime.Today.AddDays(1));
var testInfo = new CultureInfo("en-US"); var headerText = GetHeaderText(visibleRange, cultureInfo);
DateNavigationHeaderItems.ReplaceRange([headerText]);
SelectedDateNavigationHeaderIndex = DateNavigationHeaderItems.Count > 0 ? 0 : -1;
}
private string GetHeaderText(DateRange visibleRange, CultureInfo cultureInfo)
{
var startDate = visibleRange.StartDate.Date;
var endDate = visibleRange.EndDate.Date > startDate ? visibleRange.EndDate.Date.AddDays(-1) : startDate;
switch (StatePersistenceService.CalendarDisplayType) switch (StatePersistenceService.CalendarDisplayType)
{ {
case CalendarDisplayType.Day: case CalendarDisplayType.Day:
return startDate.ToString("MMMM d, dddd", cultureInfo);
case CalendarDisplayType.Week: case CalendarDisplayType.Week:
case CalendarDisplayType.WorkWeek: case CalendarDisplayType.WorkWeek:
if (startDate.Month == endDate.Month && startDate.Year == endDate.Year)
{
return $"{startDate.ToString("MMMM d", cultureInfo)} - {endDate.ToString("%d", cultureInfo)}";
}
return $"{startDate.ToString("MMMM d", cultureInfo)} - {endDate.ToString("MMMM d", cultureInfo)}";
case CalendarDisplayType.Month: case CalendarDisplayType.Month:
DateNavigationHeaderItems.ReplaceRange(testInfo.DateTimeFormat.MonthNames); return GetDominantMonthHeaderText(startDate, endDate, cultureInfo);
break;
case CalendarDisplayType.Year:
break;
default: default:
break; return startDate.ToString("d", cultureInfo);
} }
SetDateNavigationHeaderItems();
} }
partial void OnHighlightedDateRangeChanged(DateRange value) => SetDateNavigationHeaderItems(); private static string GetDominantMonthHeaderText(DateTime startDate, DateTime endDate, CultureInfo cultureInfo)
private void SetDateNavigationHeaderItems()
{ {
if (HighlightedDateRange == null) return; if (endDate < startDate)
if (DateNavigationHeaderItems.Count == 0)
{ {
UpdateDateNavigationHeaderItems(); endDate = startDate;
} }
// TODO: Year view var monthDayCounts = new Dictionary<(int Year, int Month), int>();
var monthIndex = HighlightedDateRange.GetMostVisibleMonthIndex();
SelectedDateNavigationHeaderIndex = Math.Max(monthIndex - 1, -1); for (var day = startDate; day <= endDate; day = day.AddDays(1))
{
var key = (day.Year, day.Month);
if (monthDayCounts.TryGetValue(key, out var count))
{
monthDayCounts[key] = count + 1;
}
else
{
monthDayCounts[key] = 1;
}
}
var dominantKey = (Year: startDate.Year, Month: startDate.Month);
var dominantCount = -1;
foreach (var pair in monthDayCounts)
{
if (pair.Value > dominantCount)
{
dominantCount = pair.Value;
dominantKey = pair.Key;
}
}
return new DateTime(dominantKey.Year, dominantKey.Month, 1).ToString("Y", cultureInfo);
} }
partial void OnHighlightedDateRangeChanged(DateRange value) => UpdateDateNavigationHeaderItems();
public async void Receive(CalendarEnableStatusChangedMessage message) public async void Receive(CalendarEnableStatusChangedMessage message)
=> await ExecuteUIThread(() => IsCalendarEnabled = message.IsEnabled); => await ExecuteUIThread(() => IsCalendarEnabled = message.IsEnabled);
public void Receive(NavigateManageAccountsRequested message) => SelectedMenuItemIndex = 1; public void Receive(NavigateManageAccountsRequested message) => SelectedMenuItemIndex = 1;
public void Receive(CalendarDisplayTypeChangedMessage message) => OnPropertyChanged(nameof(IsVerticalCalendar)); public void Receive(CalendarDisplayTypeChangedMessage message)
{
OnPropertyChanged(nameof(IsVerticalCalendar));
UpdateDateNavigationHeaderItems();
}
} }
@@ -232,7 +232,14 @@ public partial class CalendarPageViewModel : CalendarBaseViewModel,
{ {
base.OnNavigatedTo(mode, parameters); base.OnNavigatedTo(mode, parameters);
if (mode == NavigationMode.Back) return; if (mode == NavigationMode.Back)
{
// We unregister recipients on navigate-away, so mutations that happened while this page
// was not active (e.g. CalendarItemDeleted from details page) can be missed.
// Rehydrate currently visible ranges to guarantee UI and DB are consistent on return.
_ = RefreshVisibleRangesAsync();
return;
}
RefreshSettings(); RefreshSettings();
@@ -682,6 +689,34 @@ public partial class CalendarPageViewModel : CalendarBaseViewModel,
} }
} }
private async Task RefreshVisibleRangesAsync()
{
try
{
await _calendarLoadingSemaphore.WaitAsync().ConfigureAwait(false);
if (DayRanges == null || DayRanges.Count == 0)
return;
RefreshSettings();
foreach (var dayRange in DayRanges)
{
await InitializeCalendarEventsForDayRangeAsync(dayRange).ConfigureAwait(false);
}
FilterActiveCalendars(DayRanges);
}
catch (Exception ex)
{
Log.Error(ex, "Failed to refresh calendar ranges after navigation back.");
}
finally
{
_calendarLoadingSemaphore.Release();
}
}
private async Task TryConsolidateItemsAsync() private async Task TryConsolidateItemsAsync()
{ {
// Check if trimming is necessary // Check if trimming is necessary
@@ -1,5 +1,7 @@
using Windows.UI.Xaml.Automation.Peers; using Windows.UI.Xaml;
using Windows.UI.Xaml.Automation.Peers;
using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls;
using Wino.Core.Domain.Enums;
namespace Wino.Calendar.Controls; namespace Wino.Calendar.Controls;
@@ -8,35 +10,73 @@ namespace Wino.Calendar.Controls;
/// </summary> /// </summary>
public partial class CustomCalendarFlipView : FlipView public partial class CustomCalendarFlipView : FlipView
{ {
private const string PART_PreviousButton = "PreviousButtonHorizontal"; private const string PART_PreviousButtonHorizontal = "PreviousButtonHorizontal";
private const string PART_NextButton = "NextButtonHorizontal"; private const string PART_NextButtonHorizontal = "NextButtonHorizontal";
private const string PART_PreviousButtonVertical = "PreviousButtonVertical";
private const string PART_NextButtonVertical = "NextButtonVertical";
private Button PreviousButton; public static readonly DependencyProperty DisplayTypeProperty = DependencyProperty.Register(
private Button NextButton; nameof(DisplayType),
typeof(CalendarDisplayType),
typeof(CustomCalendarFlipView),
new PropertyMetadata(CalendarDisplayType.Week));
public CalendarDisplayType DisplayType
{
get => (CalendarDisplayType)GetValue(DisplayTypeProperty);
set => SetValue(DisplayTypeProperty, value);
}
private Button PreviousButtonHorizontal;
private Button NextButtonHorizontal;
private Button PreviousButtonVertical;
private Button NextButtonVertical;
protected override void OnApplyTemplate() protected override void OnApplyTemplate()
{ {
base.OnApplyTemplate(); base.OnApplyTemplate();
PreviousButton = GetTemplateChild(PART_PreviousButton) as Button; PreviousButtonHorizontal = GetTemplateChild(PART_PreviousButtonHorizontal) as Button;
NextButton = GetTemplateChild(PART_NextButton) as Button; NextButtonHorizontal = GetTemplateChild(PART_NextButtonHorizontal) as Button;
PreviousButtonVertical = GetTemplateChild(PART_PreviousButtonVertical) as Button;
NextButtonVertical = GetTemplateChild(PART_NextButtonVertical) as Button;
// Hide navigation buttons // Hide navigation buttons
PreviousButton.Opacity = NextButton.Opacity = 0; HideButton(PreviousButtonHorizontal);
PreviousButton.IsHitTestVisible = NextButton.IsHitTestVisible = false; HideButton(NextButtonHorizontal);
HideButton(PreviousButtonVertical);
HideButton(NextButtonVertical);
}
var t = FindName("ScrollingHost"); private static void HideButton(Button button)
{
if (button == null) return;
button.Opacity = 0;
button.IsHitTestVisible = false;
} }
public void GoPreviousFlip() public void GoPreviousFlip()
{ {
var backPeer = new ButtonAutomationPeer(PreviousButton); var previousButton = DisplayType == CalendarDisplayType.Month
? PreviousButtonVertical ?? PreviousButtonHorizontal
: PreviousButtonHorizontal ?? PreviousButtonVertical;
if (previousButton == null) return;
var backPeer = new ButtonAutomationPeer(previousButton);
backPeer.Invoke(); backPeer.Invoke();
} }
public void GoNextFlip() public void GoNextFlip()
{ {
var nextPeer = new ButtonAutomationPeer(NextButton); var nextButton = DisplayType == CalendarDisplayType.Month
? NextButtonVertical ?? NextButtonHorizontal
: NextButtonHorizontal ?? NextButtonVertical;
if (nextButton == null) return;
var nextPeer = new ButtonAutomationPeer(nextButton);
nextPeer.Invoke(); nextPeer.Invoke();
} }
} }
+79 -6
View File
@@ -1,6 +1,9 @@
using System; using System;
using System.Collections.Specialized;
using System.Linq;
using Windows.UI.Xaml; using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls;
using Wino.Core.Domain.Collections;
using Wino.Core.Domain.Models.Calendar; using Wino.Core.Domain.Models.Calendar;
namespace Wino.Calendar.Controls; namespace Wino.Calendar.Controls;
@@ -10,7 +13,6 @@ public partial class DayColumnControl : Control
private const string PART_HeaderDateDayText = nameof(PART_HeaderDateDayText); private const string PART_HeaderDateDayText = nameof(PART_HeaderDateDayText);
private const string PART_IsTodayBorder = nameof(PART_IsTodayBorder); private const string PART_IsTodayBorder = nameof(PART_IsTodayBorder);
private const string PART_ColumnHeaderText = nameof(PART_ColumnHeaderText); private const string PART_ColumnHeaderText = nameof(PART_ColumnHeaderText);
private const string PART_AllDayItemsControl = nameof(PART_AllDayItemsControl); private const string PART_AllDayItemsControl = nameof(PART_AllDayItemsControl);
private const string TodayState = nameof(TodayState); private const string TodayState = nameof(TodayState);
@@ -20,6 +22,7 @@ public partial class DayColumnControl : Control
private TextBlock ColumnHeaderText; private TextBlock ColumnHeaderText;
private Border IsTodayBorder; private Border IsTodayBorder;
private ItemsControl AllDayItemsControl; private ItemsControl AllDayItemsControl;
private CalendarEventCollection _boundEventsCollection;
public CalendarDayModel DayModel public CalendarDayModel DayModel
{ {
@@ -27,11 +30,16 @@ public partial class DayColumnControl : Control
set { SetValue(DayModelProperty, value); } set { SetValue(DayModelProperty, value); }
} }
public static readonly DependencyProperty DayModelProperty = DependencyProperty.Register(nameof(DayModel), typeof(CalendarDayModel), typeof(DayColumnControl), new PropertyMetadata(null, new PropertyChangedCallback(OnRenderingPropertiesChanged))); public static readonly DependencyProperty DayModelProperty = DependencyProperty.Register(
nameof(DayModel),
typeof(CalendarDayModel),
typeof(DayColumnControl),
new PropertyMetadata(null, new PropertyChangedCallback(OnRenderingPropertiesChanged)));
public DayColumnControl() public DayColumnControl()
{ {
DefaultStyleKey = typeof(DayColumnControl); DefaultStyleKey = typeof(DayColumnControl);
Unloaded += OnUnloaded;
} }
protected override void OnApplyTemplate() protected override void OnApplyTemplate()
@@ -43,6 +51,7 @@ public partial class DayColumnControl : Control
IsTodayBorder = GetTemplateChild(PART_IsTodayBorder) as Border; IsTodayBorder = GetTemplateChild(PART_IsTodayBorder) as Border;
AllDayItemsControl = GetTemplateChild(PART_AllDayItemsControl) as ItemsControl; AllDayItemsControl = GetTemplateChild(PART_AllDayItemsControl) as ItemsControl;
RegisterEventsCollectionHandlers();
UpdateValues(); UpdateValues();
} }
@@ -50,15 +59,78 @@ public partial class DayColumnControl : Control
{ {
if (control is DayColumnControl columnControl) if (control is DayColumnControl columnControl)
{ {
columnControl.RegisterEventsCollectionHandlers();
columnControl.UpdateValues(); columnControl.UpdateValues();
} }
} }
private void OnUnloaded(object sender, RoutedEventArgs e)
{
DeregisterEventsCollectionHandlers();
}
private bool IsMonthlyTemplate() => ColumnHeaderText == null;
private void RegisterEventsCollectionHandlers()
{
var nextCollection = DayModel?.EventsCollection;
if (ReferenceEquals(_boundEventsCollection, nextCollection))
return;
DeregisterEventsCollectionHandlers();
_boundEventsCollection = nextCollection;
if (_boundEventsCollection == null)
return;
((INotifyCollectionChanged)_boundEventsCollection.AllDayEvents).CollectionChanged += EventsCollectionChanged;
((INotifyCollectionChanged)_boundEventsCollection.RegularEvents).CollectionChanged += EventsCollectionChanged;
}
private void DeregisterEventsCollectionHandlers()
{
if (_boundEventsCollection == null)
return;
((INotifyCollectionChanged)_boundEventsCollection.AllDayEvents).CollectionChanged -= EventsCollectionChanged;
((INotifyCollectionChanged)_boundEventsCollection.RegularEvents).CollectionChanged -= EventsCollectionChanged;
_boundEventsCollection = null;
}
private void EventsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
UpdateEventItemsSource();
}
private void UpdateEventItemsSource()
{
if (AllDayItemsControl == null || DayModel == null) return;
if (IsMonthlyTemplate())
{
// Month cells should show all events for the day, not only all-day/multi-day.
var monthlyItems = DayModel.EventsCollection.AllDayEvents
.Concat(DayModel.EventsCollection.RegularEvents)
.GroupBy(a => a.Id)
.Select(g => g.First())
.OrderBy(a => a.StartDate)
.ToList();
AllDayItemsControl.ItemsSource = monthlyItems;
return;
}
AllDayItemsControl.ItemsSource = DayModel.EventsCollection.AllDayEvents;
}
private void UpdateValues() private void UpdateValues()
{ {
if (HeaderDateDayText == null || IsTodayBorder == null || DayModel == null) return; if (DayModel == null) return;
HeaderDateDayText.Text = DayModel.RepresentingDate.Day.ToString(); if (HeaderDateDayText != null)
{
HeaderDateDayText.Text = DayModel.RepresentingDate.Day.ToString();
}
// Monthly template does not use it. // Monthly template does not use it.
if (ColumnHeaderText != null) if (ColumnHeaderText != null)
@@ -66,8 +138,9 @@ public partial class DayColumnControl : Control
ColumnHeaderText.Text = DayModel.RepresentingDate.ToString("dddd", DayModel.CalendarRenderOptions.CalendarSettings.CultureInfo); ColumnHeaderText.Text = DayModel.RepresentingDate.ToString("dddd", DayModel.CalendarRenderOptions.CalendarSettings.CultureInfo);
} }
AllDayItemsControl.ItemsSource = DayModel.EventsCollection.AllDayEvents; UpdateEventItemsSource();
if (IsTodayBorder == null) return;
bool isToday = DayModel.RepresentingDate.Date == DateTime.Now.Date; bool isToday = DayModel.RepresentingDate.Date == DateTime.Now.Date;
VisualStateManager.GoToState(this, isToday ? TodayState : NotTodayState, false); VisualStateManager.GoToState(this, isToday ? TodayState : NotTodayState, false);
+17 -1
View File
@@ -34,7 +34,7 @@ public partial class WinoCalendarControl : Control
public static readonly DependencyProperty VerticalItemsPanelTemplateProperty = DependencyProperty.Register(nameof(VerticalItemsPanelTemplate), typeof(ItemsPanelTemplate), typeof(WinoCalendarControl), new PropertyMetadata(null, new PropertyChangedCallback(OnCalendarOrientationPropertiesUpdated))); public static readonly DependencyProperty VerticalItemsPanelTemplateProperty = DependencyProperty.Register(nameof(VerticalItemsPanelTemplate), typeof(ItemsPanelTemplate), typeof(WinoCalendarControl), new PropertyMetadata(null, new PropertyChangedCallback(OnCalendarOrientationPropertiesUpdated)));
public static readonly DependencyProperty HorizontalItemsPanelTemplateProperty = DependencyProperty.Register(nameof(HorizontalItemsPanelTemplate), typeof(ItemsPanelTemplate), typeof(WinoCalendarControl), new PropertyMetadata(null, new PropertyChangedCallback(OnCalendarOrientationPropertiesUpdated))); public static readonly DependencyProperty HorizontalItemsPanelTemplateProperty = DependencyProperty.Register(nameof(HorizontalItemsPanelTemplate), typeof(ItemsPanelTemplate), typeof(WinoCalendarControl), new PropertyMetadata(null, new PropertyChangedCallback(OnCalendarOrientationPropertiesUpdated)));
public static readonly DependencyProperty OrientationProperty = DependencyProperty.Register(nameof(Orientation), typeof(CalendarOrientation), typeof(WinoCalendarControl), new PropertyMetadata(CalendarOrientation.Horizontal, new PropertyChangedCallback(OnCalendarOrientationPropertiesUpdated))); public static readonly DependencyProperty OrientationProperty = DependencyProperty.Register(nameof(Orientation), typeof(CalendarOrientation), typeof(WinoCalendarControl), new PropertyMetadata(CalendarOrientation.Horizontal, new PropertyChangedCallback(OnCalendarOrientationPropertiesUpdated)));
public static readonly DependencyProperty DisplayTypeProperty = DependencyProperty.Register(nameof(DisplayType), typeof(CalendarDisplayType), typeof(WinoCalendarControl), new PropertyMetadata(CalendarDisplayType.Day)); public static readonly DependencyProperty DisplayTypeProperty = DependencyProperty.Register(nameof(DisplayType), typeof(CalendarDisplayType), typeof(WinoCalendarControl), new PropertyMetadata(CalendarDisplayType.Day, new PropertyChangedCallback(OnDisplayTypeChanged)));
/// <summary> /// <summary>
/// Gets or sets the day-week-month-year display type. /// Gets or sets the day-week-month-year display type.
@@ -171,6 +171,14 @@ public partial class WinoCalendarControl : Control
} }
} }
private static void OnDisplayTypeChanged(DependencyObject calendar, DependencyPropertyChangedEventArgs e)
{
if (calendar is WinoCalendarControl calendarControl)
{
calendarControl.ManageDisplayType();
}
}
private void ManageCalendarOrientation() private void ManageCalendarOrientation()
{ {
if (InternalFlipView == null || HorizontalItemsPanelTemplate == null || VerticalItemsPanelTemplate == null) return; if (InternalFlipView == null || HorizontalItemsPanelTemplate == null || VerticalItemsPanelTemplate == null) return;
@@ -178,6 +186,13 @@ public partial class WinoCalendarControl : Control
InternalFlipView.ItemsPanel = Orientation == CalendarOrientation.Horizontal ? HorizontalItemsPanelTemplate : VerticalItemsPanelTemplate; InternalFlipView.ItemsPanel = Orientation == CalendarOrientation.Horizontal ? HorizontalItemsPanelTemplate : VerticalItemsPanelTemplate;
} }
private void ManageDisplayType()
{
if (InternalFlipView == null) return;
InternalFlipView.DisplayType = DisplayType;
}
private void ManageHighlightedDateRange() private void ManageHighlightedDateRange()
=> SelectedFlipViewDayRange = InternalFlipView.SelectedItem as DayRangeRenderModel; => SelectedFlipViewDayRange = InternalFlipView.SelectedItem as DayRangeRenderModel;
@@ -232,6 +247,7 @@ public partial class WinoCalendarControl : Control
UpdateIdleState(); UpdateIdleState();
ManageCalendarOrientation(); ManageCalendarOrientation();
ManageDisplayType();
} }
private void UpdateIdleState() private void UpdateIdleState()
@@ -12,9 +12,12 @@ public partial class WinoCalendarTypeSelectorControl : Control
private const string PART_DayToggle = nameof(PART_DayToggle); private const string PART_DayToggle = nameof(PART_DayToggle);
private const string PART_WeekToggle = nameof(PART_WeekToggle); private const string PART_WeekToggle = nameof(PART_WeekToggle);
private const string PART_MonthToggle = nameof(PART_MonthToggle); private const string PART_MonthToggle = nameof(PART_MonthToggle);
private const string PART_YearToggle = nameof(PART_YearToggle);
public static readonly DependencyProperty SelectedTypeProperty = DependencyProperty.Register(nameof(SelectedType), typeof(CalendarDisplayType), typeof(WinoCalendarTypeSelectorControl), new PropertyMetadata(CalendarDisplayType.Week)); public static readonly DependencyProperty SelectedTypeProperty = DependencyProperty.Register(
nameof(SelectedType),
typeof(CalendarDisplayType),
typeof(WinoCalendarTypeSelectorControl),
new PropertyMetadata(CalendarDisplayType.Week, new PropertyChangedCallback(OnSelectedTypeChanged)));
public static readonly DependencyProperty DisplayDayCountProperty = DependencyProperty.Register(nameof(DisplayDayCount), typeof(int), typeof(WinoCalendarTypeSelectorControl), new PropertyMetadata(0)); public static readonly DependencyProperty DisplayDayCountProperty = DependencyProperty.Register(nameof(DisplayDayCount), typeof(int), typeof(WinoCalendarTypeSelectorControl), new PropertyMetadata(0));
public static readonly DependencyProperty TodayClickedCommandProperty = DependencyProperty.Register(nameof(TodayClickedCommand), typeof(ICommand), typeof(WinoCalendarTypeSelectorControl), new PropertyMetadata(null)); public static readonly DependencyProperty TodayClickedCommandProperty = DependencyProperty.Register(nameof(TodayClickedCommand), typeof(ICommand), typeof(WinoCalendarTypeSelectorControl), new PropertyMetadata(null));
@@ -40,7 +43,6 @@ public partial class WinoCalendarTypeSelectorControl : Control
private AppBarToggleButton _dayToggle; private AppBarToggleButton _dayToggle;
private AppBarToggleButton _weekToggle; private AppBarToggleButton _weekToggle;
private AppBarToggleButton _monthToggle; private AppBarToggleButton _monthToggle;
private AppBarToggleButton _yearToggle;
public WinoCalendarTypeSelectorControl() public WinoCalendarTypeSelectorControl()
{ {
@@ -51,24 +53,23 @@ public partial class WinoCalendarTypeSelectorControl : Control
{ {
base.OnApplyTemplate(); base.OnApplyTemplate();
UnregisterHandlers();
_todayButton = GetTemplateChild(PART_TodayButton) as AppBarButton; _todayButton = GetTemplateChild(PART_TodayButton) as AppBarButton;
_dayToggle = GetTemplateChild(PART_DayToggle) as AppBarToggleButton; _dayToggle = GetTemplateChild(PART_DayToggle) as AppBarToggleButton;
_weekToggle = GetTemplateChild(PART_WeekToggle) as AppBarToggleButton; _weekToggle = GetTemplateChild(PART_WeekToggle) as AppBarToggleButton;
_monthToggle = GetTemplateChild(PART_MonthToggle) as AppBarToggleButton; _monthToggle = GetTemplateChild(PART_MonthToggle) as AppBarToggleButton;
_yearToggle = GetTemplateChild(PART_YearToggle) as AppBarToggleButton;
Guard.IsNotNull(_todayButton, nameof(_todayButton)); Guard.IsNotNull(_todayButton, nameof(_todayButton));
Guard.IsNotNull(_dayToggle, nameof(_dayToggle)); Guard.IsNotNull(_dayToggle, nameof(_dayToggle));
Guard.IsNotNull(_weekToggle, nameof(_weekToggle)); Guard.IsNotNull(_weekToggle, nameof(_weekToggle));
Guard.IsNotNull(_monthToggle, nameof(_monthToggle)); Guard.IsNotNull(_monthToggle, nameof(_monthToggle));
Guard.IsNotNull(_yearToggle, nameof(_yearToggle));
_todayButton.Click += TodayClicked; _todayButton.Click += TodayClicked;
_dayToggle.Click += (s, e) => { SetSelectedType(CalendarDisplayType.Day); }; _dayToggle.Click += (s, e) => { SetSelectedType(CalendarDisplayType.Day); };
_weekToggle.Click += (s, e) => { SetSelectedType(CalendarDisplayType.Week); }; _weekToggle.Click += (s, e) => { SetSelectedType(CalendarDisplayType.Week); };
_monthToggle.Click += (s, e) => { SetSelectedType(CalendarDisplayType.Month); }; _monthToggle.Click += (s, e) => { SetSelectedType(CalendarDisplayType.Month); };
_yearToggle.Click += (s, e) => { SetSelectedType(CalendarDisplayType.Year); };
UpdateToggleButtonStates(); UpdateToggleButtonStates();
} }
@@ -81,11 +82,26 @@ public partial class WinoCalendarTypeSelectorControl : Control
UpdateToggleButtonStates(); UpdateToggleButtonStates();
} }
private static void OnSelectedTypeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = d as WinoCalendarTypeSelectorControl;
control?.UpdateToggleButtonStates();
}
private void UnregisterHandlers()
{
if (_todayButton != null)
{
_todayButton.Click -= TodayClicked;
}
}
private void UpdateToggleButtonStates() private void UpdateToggleButtonStates()
{ {
if (_dayToggle == null || _weekToggle == null || _monthToggle == null) return;
_dayToggle.IsChecked = SelectedType == CalendarDisplayType.Day; _dayToggle.IsChecked = SelectedType == CalendarDisplayType.Day;
_weekToggle.IsChecked = SelectedType == CalendarDisplayType.Week; _weekToggle.IsChecked = SelectedType == CalendarDisplayType.Week;
_monthToggle.IsChecked = SelectedType == CalendarDisplayType.Month; _monthToggle.IsChecked = SelectedType == CalendarDisplayType.Month;
_yearToggle.IsChecked = SelectedType == CalendarDisplayType.Year;
} }
} }
@@ -22,8 +22,6 @@ public partial class WinoCalendarItemTemplateSelector : DataTemplateSelector
return DayWeekWorkWeekTemplate; return DayWeekWorkWeekTemplate;
case CalendarDisplayType.Month: case CalendarDisplayType.Month:
return MonthlyTemplate; return MonthlyTemplate;
case CalendarDisplayType.Year:
break;
default: default:
break; break;
} }
@@ -367,6 +367,9 @@
<RowDefinition Height="*" MinHeight="35" /> <RowDefinition Height="*" MinHeight="35" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<!-- Day number -->
<TextBlock x:Name="PART_HeaderDateDayText" FontSize="17" />
<!-- Extras --> <!-- Extras -->
<StackPanel Grid.Column="1" HorizontalAlignment="Right" /> <StackPanel Grid.Column="1" HorizontalAlignment="Right" />
@@ -61,16 +61,6 @@
</AppBarToggleButton.Icon> </AppBarToggleButton.Icon>
</AppBarToggleButton> </AppBarToggleButton>
<!-- Year -->
<AppBarToggleButton
x:Name="PART_YearToggle"
Foreground="{ThemeResource ApplicationForegroundThemeBrush}"
Label="Year">
<AppBarToggleButton.Icon>
<controls1:WinoFontIcon Icon="CalendarYear" />
</AppBarToggleButton.Icon>
</AppBarToggleButton>
</CommandBar.PrimaryCommands> </CommandBar.PrimaryCommands>
</CommandBar> </CommandBar>
</ControlTemplate> </ControlTemplate>
+2 -1
View File
@@ -1,4 +1,4 @@
<abstract:AppShellAbstract <abstract:AppShellAbstract
x:Class="Wino.Calendar.Views.AppShell" x:Class="Wino.Calendar.Views.AppShell"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
@@ -119,6 +119,7 @@
FontSize="14" FontSize="14"
FontWeight="Normal" FontWeight="Normal"
IsHitTestVisible="False" IsHitTestVisible="False"
DisplayType="{x:Bind ViewModel.StatePersistenceService.CalendarDisplayType, Mode=OneWay}"
ItemsSource="{x:Bind ViewModel.DateNavigationHeaderItems}" ItemsSource="{x:Bind ViewModel.DateNavigationHeaderItems}"
SelectedIndex="{x:Bind ViewModel.SelectedDateNavigationHeaderIndex, Mode=OneWay}"> SelectedIndex="{x:Bind ViewModel.SelectedDateNavigationHeaderIndex, Mode=OneWay}">
<FlipView.ItemTemplate> <FlipView.ItemTemplate>
+4 -4
View File
@@ -20,13 +20,13 @@ public sealed partial class AppShell : AppShellAbstract,
InitializeComponent(); InitializeComponent();
Window.Current.SetTitleBar(DragArea); Window.Current.SetTitleBar(DragArea);
ManageCalendarDisplayType(); ManageCalendarDisplayType(ViewModel.StatePersistenceService.CalendarDisplayType);
} }
private void ManageCalendarDisplayType() private void ManageCalendarDisplayType(Core.Domain.Enums.CalendarDisplayType displayType)
{ {
// Go to different states based on the display type. // Go to different states based on the display type.
if (ViewModel.IsVerticalCalendar) if (displayType == Core.Domain.Enums.CalendarDisplayType.Month)
{ {
VisualStateManager.GoToState(this, STATE_VerticalCalendar, false); VisualStateManager.GoToState(this, STATE_VerticalCalendar, false);
} }
@@ -42,7 +42,7 @@ public sealed partial class AppShell : AppShellAbstract,
public void Receive(CalendarDisplayTypeChangedMessage message) public void Receive(CalendarDisplayTypeChangedMessage message)
{ {
ManageCalendarDisplayType(); ManageCalendarDisplayType(message.NewDisplayType);
} }
private void ShellFrameContentNavigated(object sender, Windows.UI.Xaml.Navigation.NavigationEventArgs e) private void ShellFrameContentNavigated(object sender, Windows.UI.Xaml.Navigation.NavigationEventArgs e)
@@ -5,6 +5,5 @@ public enum CalendarDisplayType
Day, Day,
Week, Week,
WorkWeek, WorkWeek,
Month, Month
Year
} }
@@ -1,7 +1,8 @@
using System.Linq; using System.Linq;
using Microsoft.UI.Xaml; using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Automation.Peers; using Microsoft.UI.Xaml.Automation.Peers;
using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Controls;
using Wino.Core.Domain.Enums;
using Wino.Mail.WinUI.Controls.CalendarFlipView; using Wino.Mail.WinUI.Controls.CalendarFlipView;
namespace Wino.Calendar.Controls; namespace Wino.Calendar.Controls;
@@ -11,27 +12,56 @@ namespace Wino.Calendar.Controls;
/// </summary> /// </summary>
public partial class CustomCalendarFlipView : FlipView public partial class CustomCalendarFlipView : FlipView
{ {
private const string PART_PreviousButton = "PreviousButtonHorizontal"; private const string PART_PreviousButtonHorizontal = "PreviousButtonHorizontal";
private const string PART_NextButton = "NextButtonHorizontal"; private const string PART_NextButtonHorizontal = "NextButtonHorizontal";
private const string PART_PreviousButtonVertical = "PreviousButtonVertical";
private const string PART_NextButtonVertical = "NextButtonVertical";
private Button? PreviousButton; public static readonly DependencyProperty DisplayTypeProperty = DependencyProperty.Register(
private Button? NextButton; nameof(DisplayType),
typeof(CalendarDisplayType),
typeof(CustomCalendarFlipView),
new PropertyMetadata(CalendarDisplayType.Week));
public CalendarDisplayType DisplayType
{
get => (CalendarDisplayType)GetValue(DisplayTypeProperty);
set => SetValue(DisplayTypeProperty, value);
}
private Button? PreviousButtonHorizontal;
private Button? NextButtonHorizontal;
private Button? PreviousButtonVertical;
private Button? NextButtonVertical;
protected override void OnApplyTemplate() protected override void OnApplyTemplate()
{ {
base.OnApplyTemplate(); base.OnApplyTemplate();
PreviousButton = (Button)GetTemplateChild(PART_PreviousButton); PreviousButtonHorizontal = GetTemplateChild(PART_PreviousButtonHorizontal) as Button;
NextButton = (Button)GetTemplateChild(PART_NextButton); NextButtonHorizontal = GetTemplateChild(PART_NextButtonHorizontal) as Button;
PreviousButtonVertical = GetTemplateChild(PART_PreviousButtonVertical) as Button;
NextButtonVertical = GetTemplateChild(PART_NextButtonVertical) as Button;
// Hide navigation buttons // Hide navigation buttons
PreviousButton.Opacity = NextButton.Opacity = 0; HideButton(PreviousButtonHorizontal);
PreviousButton.IsHitTestVisible = NextButton.IsHitTestVisible = false; HideButton(NextButtonHorizontal);
HideButton(PreviousButtonVertical);
HideButton(NextButtonVertical);
this.SelectionChanged += FlipViewSelectionChanged; SelectionChanged += FlipViewSelectionChanged;
} }
private void FlipViewSelectionChanged(object sender, SelectionChangedEventArgs e) => OnSelectedItemChanged(e.RemovedItems.FirstOrDefault(), e.AddedItems.FirstOrDefault()); private static void HideButton(Button? button)
{
if (button == null) return;
button.Opacity = 0;
button.IsHitTestVisible = false;
}
private void FlipViewSelectionChanged(object sender, SelectionChangedEventArgs e)
=> OnSelectedItemChanged(e.RemovedItems.FirstOrDefault(), e.AddedItems.FirstOrDefault());
protected virtual void OnSelectedItemChanged(object oldValue, object newValue) { } protected virtual void OnSelectedItemChanged(object oldValue, object newValue) { }
@@ -47,13 +77,25 @@ public partial class CustomCalendarFlipView : FlipView
public void GoPreviousFlip() public void GoPreviousFlip()
{ {
var backPeer = new ButtonAutomationPeer(PreviousButton); var previousButton = DisplayType == CalendarDisplayType.Month
? PreviousButtonVertical ?? PreviousButtonHorizontal
: PreviousButtonHorizontal ?? PreviousButtonVertical;
if (previousButton == null) return;
var backPeer = new ButtonAutomationPeer(previousButton);
backPeer.Invoke(); backPeer.Invoke();
} }
public void GoNextFlip() public void GoNextFlip()
{ {
var nextPeer = new ButtonAutomationPeer(NextButton); var nextButton = DisplayType == CalendarDisplayType.Month
? NextButtonVertical ?? NextButtonHorizontal
: NextButtonHorizontal ?? NextButtonVertical;
if (nextButton == null) return;
var nextPeer = new ButtonAutomationPeer(nextButton);
nextPeer.Invoke(); nextPeer.Invoke();
} }
} }
@@ -1,6 +1,9 @@
using System; using System;
using System.Collections.Specialized;
using System.Linq;
using Microsoft.UI.Xaml; using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Controls;
using Wino.Core.Domain.Collections;
using Wino.Core.Domain.Models.Calendar; using Wino.Core.Domain.Models.Calendar;
namespace Wino.Calendar.Controls; namespace Wino.Calendar.Controls;
@@ -10,7 +13,6 @@ public partial class DayColumnControl : Control
private const string PART_HeaderDateDayText = nameof(PART_HeaderDateDayText); private const string PART_HeaderDateDayText = nameof(PART_HeaderDateDayText);
private const string PART_IsTodayBorder = nameof(PART_IsTodayBorder); private const string PART_IsTodayBorder = nameof(PART_IsTodayBorder);
private const string PART_ColumnHeaderText = nameof(PART_ColumnHeaderText); private const string PART_ColumnHeaderText = nameof(PART_ColumnHeaderText);
private const string PART_AllDayItemsControl = nameof(PART_AllDayItemsControl); private const string PART_AllDayItemsControl = nameof(PART_AllDayItemsControl);
private const string TodayState = nameof(TodayState); private const string TodayState = nameof(TodayState);
@@ -20,6 +22,7 @@ public partial class DayColumnControl : Control
private TextBlock ColumnHeaderText; private TextBlock ColumnHeaderText;
private Border IsTodayBorder; private Border IsTodayBorder;
private ItemsControl AllDayItemsControl; private ItemsControl AllDayItemsControl;
private CalendarEventCollection _boundEventsCollection;
public CalendarDayModel DayModel public CalendarDayModel DayModel
{ {
@@ -27,11 +30,16 @@ public partial class DayColumnControl : Control
set { SetValue(DayModelProperty, value); } set { SetValue(DayModelProperty, value); }
} }
public static readonly DependencyProperty DayModelProperty = DependencyProperty.Register(nameof(DayModel), typeof(CalendarDayModel), typeof(DayColumnControl), new PropertyMetadata(null, new PropertyChangedCallback(OnRenderingPropertiesChanged))); public static readonly DependencyProperty DayModelProperty = DependencyProperty.Register(
nameof(DayModel),
typeof(CalendarDayModel),
typeof(DayColumnControl),
new PropertyMetadata(null, new PropertyChangedCallback(OnRenderingPropertiesChanged)));
public DayColumnControl() public DayColumnControl()
{ {
DefaultStyleKey = typeof(DayColumnControl); DefaultStyleKey = typeof(DayColumnControl);
Unloaded += OnUnloaded;
} }
protected override void OnApplyTemplate() protected override void OnApplyTemplate()
@@ -43,6 +51,7 @@ public partial class DayColumnControl : Control
IsTodayBorder = GetTemplateChild(PART_IsTodayBorder) as Border; IsTodayBorder = GetTemplateChild(PART_IsTodayBorder) as Border;
AllDayItemsControl = GetTemplateChild(PART_AllDayItemsControl) as ItemsControl; AllDayItemsControl = GetTemplateChild(PART_AllDayItemsControl) as ItemsControl;
RegisterEventsCollectionHandlers();
UpdateValues(); UpdateValues();
} }
@@ -50,15 +59,78 @@ public partial class DayColumnControl : Control
{ {
if (control is DayColumnControl columnControl) if (control is DayColumnControl columnControl)
{ {
columnControl.RegisterEventsCollectionHandlers();
columnControl.UpdateValues(); columnControl.UpdateValues();
} }
} }
private void OnUnloaded(object sender, RoutedEventArgs e)
{
DeregisterEventsCollectionHandlers();
}
private bool IsMonthlyTemplate() => ColumnHeaderText == null;
private void RegisterEventsCollectionHandlers()
{
var nextCollection = DayModel?.EventsCollection;
if (ReferenceEquals(_boundEventsCollection, nextCollection))
return;
DeregisterEventsCollectionHandlers();
_boundEventsCollection = nextCollection;
if (_boundEventsCollection == null)
return;
((INotifyCollectionChanged)_boundEventsCollection.AllDayEvents).CollectionChanged += EventsCollectionChanged;
((INotifyCollectionChanged)_boundEventsCollection.RegularEvents).CollectionChanged += EventsCollectionChanged;
}
private void DeregisterEventsCollectionHandlers()
{
if (_boundEventsCollection == null)
return;
((INotifyCollectionChanged)_boundEventsCollection.AllDayEvents).CollectionChanged -= EventsCollectionChanged;
((INotifyCollectionChanged)_boundEventsCollection.RegularEvents).CollectionChanged -= EventsCollectionChanged;
_boundEventsCollection = null;
}
private void EventsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
UpdateEventItemsSource();
}
private void UpdateEventItemsSource()
{
if (AllDayItemsControl == null || DayModel == null) return;
if (IsMonthlyTemplate())
{
// Month cells should show all events for the day, not only all-day/multi-day.
var monthlyItems = DayModel.EventsCollection.AllDayEvents
.Concat(DayModel.EventsCollection.RegularEvents)
.GroupBy(a => a.Id)
.Select(g => g.First())
.OrderBy(a => a.StartDate)
.ToList();
AllDayItemsControl.ItemsSource = monthlyItems;
return;
}
AllDayItemsControl.ItemsSource = DayModel.EventsCollection.AllDayEvents;
}
private void UpdateValues() private void UpdateValues()
{ {
if (HeaderDateDayText == null || IsTodayBorder == null || DayModel == null) return; if (DayModel == null) return;
HeaderDateDayText.Text = DayModel.RepresentingDate.Day.ToString(); if (HeaderDateDayText != null)
{
HeaderDateDayText.Text = DayModel.RepresentingDate.Day.ToString();
}
// Monthly template does not use it. // Monthly template does not use it.
if (ColumnHeaderText != null) if (ColumnHeaderText != null)
@@ -66,8 +138,9 @@ public partial class DayColumnControl : Control
ColumnHeaderText.Text = DayModel.RepresentingDate.ToString("dddd", DayModel.CalendarRenderOptions.CalendarSettings.CultureInfo); ColumnHeaderText.Text = DayModel.RepresentingDate.ToString("dddd", DayModel.CalendarRenderOptions.CalendarSettings.CultureInfo);
} }
AllDayItemsControl.ItemsSource = DayModel.EventsCollection.AllDayEvents; UpdateEventItemsSource();
if (IsTodayBorder == null) return;
bool isToday = DayModel.RepresentingDate.Date == DateTime.Now.Date; bool isToday = DayModel.RepresentingDate.Date == DateTime.Now.Date;
VisualStateManager.GoToState(this, isToday ? TodayState : NotTodayState, false); VisualStateManager.GoToState(this, isToday ? TodayState : NotTodayState, false);
@@ -87,6 +87,9 @@ public partial class WinoCalendarControl : Control
partial void OnOrientationChanged(CalendarOrientation newValue) partial void OnOrientationChanged(CalendarOrientation newValue)
=> ManageCalendarOrientation(); => ManageCalendarOrientation();
partial void OnDisplayTypeChanged(CalendarDisplayType newValue)
=> ManageDisplayType();
partial void OnIsFlipIdleChanged(bool newValue) partial void OnIsFlipIdleChanged(bool newValue)
=> UpdateIdleState(); => UpdateIdleState();
@@ -131,6 +134,13 @@ public partial class WinoCalendarControl : Control
InternalFlipView.ItemsPanel = Orientation == CalendarOrientation.Horizontal ? HorizontalItemsPanelTemplate : VerticalItemsPanelTemplate; InternalFlipView.ItemsPanel = Orientation == CalendarOrientation.Horizontal ? HorizontalItemsPanelTemplate : VerticalItemsPanelTemplate;
} }
private void ManageDisplayType()
{
if (InternalFlipView == null) return;
InternalFlipView.DisplayType = DisplayType;
}
private void ManageHighlightedDateRange() private void ManageHighlightedDateRange()
=> SelectedFlipViewDayRange = InternalFlipView.SelectedItem as DayRangeRenderModel; => SelectedFlipViewDayRange = InternalFlipView.SelectedItem as DayRangeRenderModel;
@@ -185,6 +195,7 @@ public partial class WinoCalendarControl : Control
UpdateIdleState(); UpdateIdleState();
ManageCalendarOrientation(); ManageCalendarOrientation();
ManageDisplayType();
} }
private void UpdateIdleState() private void UpdateIdleState()
@@ -12,9 +12,12 @@ public partial class WinoCalendarTypeSelectorControl : Control
private const string PART_DayToggle = nameof(PART_DayToggle); private const string PART_DayToggle = nameof(PART_DayToggle);
private const string PART_WeekToggle = nameof(PART_WeekToggle); private const string PART_WeekToggle = nameof(PART_WeekToggle);
private const string PART_MonthToggle = nameof(PART_MonthToggle); private const string PART_MonthToggle = nameof(PART_MonthToggle);
private const string PART_YearToggle = nameof(PART_YearToggle);
public static readonly DependencyProperty SelectedTypeProperty = DependencyProperty.Register(nameof(SelectedType), typeof(CalendarDisplayType), typeof(WinoCalendarTypeSelectorControl), new PropertyMetadata(CalendarDisplayType.Week)); public static readonly DependencyProperty SelectedTypeProperty = DependencyProperty.Register(
nameof(SelectedType),
typeof(CalendarDisplayType),
typeof(WinoCalendarTypeSelectorControl),
new PropertyMetadata(CalendarDisplayType.Week, OnSelectedTypeChanged));
public static readonly DependencyProperty DisplayDayCountProperty = DependencyProperty.Register(nameof(DisplayDayCount), typeof(int), typeof(WinoCalendarTypeSelectorControl), new PropertyMetadata(0)); public static readonly DependencyProperty DisplayDayCountProperty = DependencyProperty.Register(nameof(DisplayDayCount), typeof(int), typeof(WinoCalendarTypeSelectorControl), new PropertyMetadata(0));
public static readonly DependencyProperty TodayClickedCommandProperty = DependencyProperty.Register(nameof(TodayClickedCommand), typeof(ICommand), typeof(WinoCalendarTypeSelectorControl), new PropertyMetadata(null)); public static readonly DependencyProperty TodayClickedCommandProperty = DependencyProperty.Register(nameof(TodayClickedCommand), typeof(ICommand), typeof(WinoCalendarTypeSelectorControl), new PropertyMetadata(null));
@@ -40,7 +43,6 @@ public partial class WinoCalendarTypeSelectorControl : Control
private AppBarToggleButton _dayToggle; private AppBarToggleButton _dayToggle;
private AppBarToggleButton _weekToggle; private AppBarToggleButton _weekToggle;
private AppBarToggleButton _monthToggle; private AppBarToggleButton _monthToggle;
private AppBarToggleButton _yearToggle;
public WinoCalendarTypeSelectorControl() public WinoCalendarTypeSelectorControl()
{ {
@@ -51,24 +53,23 @@ public partial class WinoCalendarTypeSelectorControl : Control
{ {
base.OnApplyTemplate(); base.OnApplyTemplate();
UnregisterHandlers();
_todayButton = GetTemplateChild(PART_TodayButton) as AppBarButton; _todayButton = GetTemplateChild(PART_TodayButton) as AppBarButton;
_dayToggle = GetTemplateChild(PART_DayToggle) as AppBarToggleButton; _dayToggle = GetTemplateChild(PART_DayToggle) as AppBarToggleButton;
_weekToggle = GetTemplateChild(PART_WeekToggle) as AppBarToggleButton; _weekToggle = GetTemplateChild(PART_WeekToggle) as AppBarToggleButton;
_monthToggle = GetTemplateChild(PART_MonthToggle) as AppBarToggleButton; _monthToggle = GetTemplateChild(PART_MonthToggle) as AppBarToggleButton;
_yearToggle = GetTemplateChild(PART_YearToggle) as AppBarToggleButton;
Guard.IsNotNull(_todayButton, nameof(_todayButton)); Guard.IsNotNull(_todayButton, nameof(_todayButton));
Guard.IsNotNull(_dayToggle, nameof(_dayToggle)); Guard.IsNotNull(_dayToggle, nameof(_dayToggle));
Guard.IsNotNull(_weekToggle, nameof(_weekToggle)); Guard.IsNotNull(_weekToggle, nameof(_weekToggle));
Guard.IsNotNull(_monthToggle, nameof(_monthToggle)); Guard.IsNotNull(_monthToggle, nameof(_monthToggle));
Guard.IsNotNull(_yearToggle, nameof(_yearToggle));
_todayButton.Click += TodayClicked; _todayButton.Click += TodayClicked;
_dayToggle.Click += (s, e) => { SetSelectedType(CalendarDisplayType.Day); }; _dayToggle.Click += (s, e) => { SetSelectedType(CalendarDisplayType.Day); };
_weekToggle.Click += (s, e) => { SetSelectedType(CalendarDisplayType.Week); }; _weekToggle.Click += (s, e) => { SetSelectedType(CalendarDisplayType.Week); };
_monthToggle.Click += (s, e) => { SetSelectedType(CalendarDisplayType.Month); }; _monthToggle.Click += (s, e) => { SetSelectedType(CalendarDisplayType.Month); };
_yearToggle.Click += (s, e) => { SetSelectedType(CalendarDisplayType.Year); };
UpdateToggleButtonStates(); UpdateToggleButtonStates();
} }
@@ -81,11 +82,29 @@ public partial class WinoCalendarTypeSelectorControl : Control
UpdateToggleButtonStates(); UpdateToggleButtonStates();
} }
private static void OnSelectedTypeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = d as WinoCalendarTypeSelectorControl;
control?.UpdateToggleButtonStates();
}
private void UnregisterHandlers()
{
if (_todayButton != null)
{
_todayButton.Click -= TodayClicked;
}
}
private void UpdateToggleButtonStates() private void UpdateToggleButtonStates()
{ {
if (_dayToggle == null || _weekToggle == null || _monthToggle == null)
{
return;
}
_dayToggle.IsChecked = SelectedType == CalendarDisplayType.Day; _dayToggle.IsChecked = SelectedType == CalendarDisplayType.Day;
_weekToggle.IsChecked = SelectedType == CalendarDisplayType.Week; _weekToggle.IsChecked = SelectedType == CalendarDisplayType.Week;
_monthToggle.IsChecked = SelectedType == CalendarDisplayType.Month; _monthToggle.IsChecked = SelectedType == CalendarDisplayType.Month;
_yearToggle.IsChecked = SelectedType == CalendarDisplayType.Year;
} }
} }
@@ -22,8 +22,6 @@ public partial class WinoCalendarItemTemplateSelector : DataTemplateSelector
return DayWeekWorkWeekTemplate; return DayWeekWorkWeekTemplate;
case CalendarDisplayType.Month: case CalendarDisplayType.Month:
return MonthlyTemplate; return MonthlyTemplate;
case CalendarDisplayType.Year:
break;
default: default:
break; break;
} }
@@ -22,7 +22,7 @@ public class StatePersistenceService : ObservableObject, IStatePersistanceServic
_openPaneLength = _configurationService.Get(OpenPaneLengthKey, 320d); _openPaneLength = _configurationService.Get(OpenPaneLengthKey, 320d);
_mailListPaneLength = _configurationService.Get(MailListPaneLengthKey, 420d); _mailListPaneLength = _configurationService.Get(MailListPaneLengthKey, 420d);
_calendarDisplayType = _configurationService.Get(nameof(CalendarDisplayType), CalendarDisplayType.Week); _calendarDisplayType = EnsureValidCalendarDisplayType(_configurationService.Get(nameof(CalendarDisplayType), CalendarDisplayType.Week));
_dayDisplayCount = _configurationService.Get(nameof(DayDisplayCount), 1); _dayDisplayCount = _configurationService.Get(nameof(DayDisplayCount), 1);
PropertyChanged += ServicePropertyChanged; PropertyChanged += ServicePropertyChanged;
@@ -176,9 +176,11 @@ public class StatePersistenceService : ObservableObject, IStatePersistanceServic
get => _calendarDisplayType; get => _calendarDisplayType;
set set
{ {
if (SetProperty(ref _calendarDisplayType, value)) var validValue = EnsureValidCalendarDisplayType(value);
if (SetProperty(ref _calendarDisplayType, validValue))
{ {
_configurationService.Set(nameof(CalendarDisplayType), value); _configurationService.Set(nameof(CalendarDisplayType), validValue);
} }
} }
} }
@@ -197,4 +199,11 @@ public class StatePersistenceService : ObservableObject, IStatePersistanceServic
} }
private void UpdateAppCoreWindowTitle() => WinoApplication.MainWindow.Title = CoreWindowTitle; private void UpdateAppCoreWindowTitle() => WinoApplication.MainWindow.Title = CoreWindowTitle;
private static CalendarDisplayType EnsureValidCalendarDisplayType(CalendarDisplayType displayType)
{
return Enum.IsDefined(typeof(CalendarDisplayType), displayType)
? displayType
: CalendarDisplayType.Week;
}
} }
@@ -390,6 +390,9 @@
<RowDefinition Height="*" MinHeight="35" /> <RowDefinition Height="*" MinHeight="35" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<!-- Day number -->
<TextBlock x:Name="PART_HeaderDateDayText" FontSize="17" />
<!-- Extras --> <!-- Extras -->
<StackPanel Grid.Column="1" HorizontalAlignment="Right" /> <StackPanel Grid.Column="1" HorizontalAlignment="Right" />
@@ -61,16 +61,6 @@
</AppBarToggleButton.Icon> </AppBarToggleButton.Icon>
</AppBarToggleButton> </AppBarToggleButton>
<!-- Year -->
<AppBarToggleButton
x:Name="PART_YearToggle"
Foreground="{ThemeResource ApplicationForegroundThemeBrush}"
Label="Year">
<AppBarToggleButton.Icon>
<controls1:WinoFontIcon Icon="CalendarYear" />
</AppBarToggleButton.Icon>
</AppBarToggleButton>
</CommandBar.PrimaryCommands> </CommandBar.PrimaryCommands>
</CommandBar> </CommandBar>
</ControlTemplate> </ControlTemplate>
@@ -1,4 +1,4 @@
<abstract:CalendarAppShellAbstract <abstract:CalendarAppShellAbstract
x:Class="Wino.Mail.WinUI.Views.Calendar.CalendarAppShell" x:Class="Wino.Mail.WinUI.Views.Calendar.CalendarAppShell"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
@@ -85,6 +85,7 @@
FontSize="14" FontSize="14"
FontWeight="Normal" FontWeight="Normal"
IsHitTestVisible="False" IsHitTestVisible="False"
DisplayType="{x:Bind ViewModel.StatePersistenceService.CalendarDisplayType, Mode=OneWay}"
ItemsSource="{x:Bind ViewModel.DateNavigationHeaderItems}" ItemsSource="{x:Bind ViewModel.DateNavigationHeaderItems}"
SelectedIndex="{x:Bind ViewModel.SelectedDateNavigationHeaderIndex, Mode=OneWay}"> SelectedIndex="{x:Bind ViewModel.SelectedDateNavigationHeaderIndex, Mode=OneWay}">
<FlipView.ItemTemplate> <FlipView.ItemTemplate>
@@ -19,13 +19,13 @@ public sealed partial class CalendarAppShell : CalendarAppShellAbstract,
InitializeComponent(); InitializeComponent();
// Window.Current.SetTitleBar(DragArea); // Window.Current.SetTitleBar(DragArea);
ManageCalendarDisplayType(); ManageCalendarDisplayType(ViewModel.StatePersistenceService.CalendarDisplayType);
} }
private void ManageCalendarDisplayType() private void ManageCalendarDisplayType(Core.Domain.Enums.CalendarDisplayType displayType)
{ {
// Go to different states based on the display type. // Go to different states based on the display type.
if (ViewModel.IsVerticalCalendar) if (displayType == Core.Domain.Enums.CalendarDisplayType.Month)
{ {
VisualStateManager.GoToState(this, STATE_VerticalCalendar, false); VisualStateManager.GoToState(this, STATE_VerticalCalendar, false);
} }
@@ -41,7 +41,7 @@ public sealed partial class CalendarAppShell : CalendarAppShellAbstract,
public void Receive(CalendarDisplayTypeChangedMessage message) public void Receive(CalendarDisplayTypeChangedMessage message)
{ {
ManageCalendarDisplayType(); ManageCalendarDisplayType(message.NewDisplayType);
} }
//private void ShellFrameContentNavigated(object sender, Microsoft.UI.Xaml.Navigation.NavigationEventArgs e) //private void ShellFrameContentNavigated(object sender, Microsoft.UI.Xaml.Navigation.NavigationEventArgs e)