diff --git a/Wino.Mail.WinUI/Controls/Calendar/WinoCalendarControl.cs b/Wino.Mail.WinUI/Controls/Calendar/WinoCalendarControl.cs index 93b02616..d9876bda 100644 --- a/Wino.Mail.WinUI/Controls/Calendar/WinoCalendarControl.cs +++ b/Wino.Mail.WinUI/Controls/Calendar/WinoCalendarControl.cs @@ -142,7 +142,14 @@ public partial class WinoCalendarControl : Control } private void ManageHighlightedDateRange() - => SelectedFlipViewDayRange = InternalFlipView.SelectedItem as DayRangeRenderModel; + { + if (InternalFlipView?.IsProgrammaticNavigationInProgress == true) + { + return; + } + + SelectedFlipViewDayRange = InternalFlipView?.SelectedItem as DayRangeRenderModel; + } private void DeregisterCanvas(WinoDayTimelineCanvas canvas) { @@ -190,14 +197,29 @@ public partial class WinoCalendarControl : Control { base.OnApplyTemplate(); + if (InternalFlipView != null) + { + InternalFlipView.ProgrammaticNavigationCompleted -= InternalFlipViewProgrammaticNavigationCompleted; + } + InternalFlipView = GetTemplateChild(PART_WinoFlipView) as WinoCalendarFlipView; IdleGrid = GetTemplateChild(PART_IdleGrid) as Grid; + if (InternalFlipView != null) + { + InternalFlipView.ProgrammaticNavigationCompleted += InternalFlipViewProgrammaticNavigationCompleted; + } + UpdateIdleState(); ManageCalendarOrientation(); ManageDisplayType(); } + private void InternalFlipViewProgrammaticNavigationCompleted(object? sender, ProgrammaticNavigationCompletedEventArgs e) + { + SelectedFlipViewDayRange = e.DayRange; + } + private void UpdateIdleState() { InternalFlipView.Opacity = IsFlipIdle ? 0 : 1; diff --git a/Wino.Mail.WinUI/Controls/Calendar/WinoCalendarFlipView.cs b/Wino.Mail.WinUI/Controls/Calendar/WinoCalendarFlipView.cs index 9bef5b1b..4017139c 100644 --- a/Wino.Mail.WinUI/Controls/Calendar/WinoCalendarFlipView.cs +++ b/Wino.Mail.WinUI/Controls/Calendar/WinoCalendarFlipView.cs @@ -43,6 +43,12 @@ public partial class WinoCalendarFlipView : CustomCalendarFlipView set { SetValue(IsIdleProperty, value); } } + internal bool IsProgrammaticNavigationInProgress { get; private set; } + + internal int? PendingTargetIndex { get; private set; } + + internal event EventHandler? ProgrammaticNavigationCompleted; + public WinoCalendarFlipView() { RegisterPropertyChangedCallback(ItemsSourceProperty, new DependencyPropertyChangedCallback(OnItemsSourceChanged)); @@ -123,37 +129,61 @@ public partial class WinoCalendarFlipView : CustomCalendarFlipView await DispatcherQueue.EnqueueAsync(() => { // Find the day range that contains the date. - var dayRange = GetItemsSource()?.FirstOrDefault(a => a.CalendarDays.Any(b => b.RepresentingDate.Date == dateTime.Date)); + var dayRanges = GetItemsSource(); + var dayRange = dayRanges?.FirstOrDefault(a => a.CalendarDays.Any(b => b.RepresentingDate.Date == dateTime.Date)); - if (dayRange != null) + if (dayRange != null && dayRanges != null) { - var navigationItemIndex = GetItemsSource().IndexOf(dayRange); + var navigationItemIndex = dayRanges.IndexOf(dayRange); + var hasNavigationWork = navigationItemIndex != SelectedIndex; - if (Math.Abs(navigationItemIndex - SelectedIndex) > 4) + IsProgrammaticNavigationInProgress = hasNavigationWork; + PendingTargetIndex = navigationItemIndex; + + if (!hasNavigationWork) { - // Difference between dates are high. - // No need to animate this much, just go without animating. - - SelectedIndex = navigationItemIndex; + PendingTargetIndex = null; + return; } - else - { - // Until we reach the day in the flip, simulate next-prev button clicks. - // This will make sure the FlipView animations are triggered. - // Setting SelectedIndex directly doesn't trigger the animations. - while (SelectedIndex != navigationItemIndex) + try + { + if (Math.Abs(navigationItemIndex - SelectedIndex) > 4) { - if (SelectedIndex > navigationItemIndex) + // Difference between dates are high. + // No need to animate this much, just go without animating. + + SelectedIndex = navigationItemIndex; + } + else + { + // Until we reach the day in the flip, simulate next-prev button clicks. + // This will make sure the FlipView animations are triggered. + // Setting SelectedIndex directly doesn't trigger the animations. + + while (SelectedIndex != navigationItemIndex) { - GoPreviousFlip(); - } - else - { - GoNextFlip(); + if (SelectedIndex > navigationItemIndex) + { + GoPreviousFlip(); + } + else + { + GoNextFlip(); + } } } } + finally + { + if (SelectedIndex == PendingTargetIndex) + { + ProgrammaticNavigationCompleted?.Invoke(this, new ProgrammaticNavigationCompletedEventArgs(SelectedItem as DayRangeRenderModel ?? dayRange)); + } + + IsProgrammaticNavigationInProgress = false; + PendingTargetIndex = null; + } } }); } @@ -161,3 +191,13 @@ public partial class WinoCalendarFlipView : CustomCalendarFlipView private ObservableRangeCollection GetItemsSource() => ItemsSource as ObservableRangeCollection; } + +internal sealed class ProgrammaticNavigationCompletedEventArgs : EventArgs +{ + public ProgrammaticNavigationCompletedEventArgs(DayRangeRenderModel dayRange) + { + DayRange = dayRange; + } + + public DayRangeRenderModel DayRange { get; } +}