Improved shell experience.
This commit is contained in:
@@ -23,7 +23,6 @@ using Wino.Core.Domain.Models.Navigation;
|
|||||||
using Wino.Core.Domain.Models.Synchronization;
|
using Wino.Core.Domain.Models.Synchronization;
|
||||||
using Wino.Core.ViewModels;
|
using Wino.Core.ViewModels;
|
||||||
using Wino.Messaging.Client.Calendar;
|
using Wino.Messaging.Client.Calendar;
|
||||||
using Wino.Messaging.Client.Navigation;
|
|
||||||
using Wino.Messaging.Server;
|
using Wino.Messaging.Server;
|
||||||
using Wino.Messaging.UI;
|
using Wino.Messaging.UI;
|
||||||
|
|
||||||
@@ -33,7 +32,6 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel,
|
|||||||
ICalendarShellClient,
|
ICalendarShellClient,
|
||||||
IRecipient<VisibleDateRangeChangedMessage>,
|
IRecipient<VisibleDateRangeChangedMessage>,
|
||||||
IRecipient<CalendarEnableStatusChangedMessage>,
|
IRecipient<CalendarEnableStatusChangedMessage>,
|
||||||
IRecipient<NavigateManageAccountsRequested>,
|
|
||||||
IRecipient<CalendarDisplayTypeChangedMessage>,
|
IRecipient<CalendarDisplayTypeChangedMessage>,
|
||||||
IRecipient<AccountRemovedMessage>
|
IRecipient<AccountRemovedMessage>
|
||||||
{
|
{
|
||||||
@@ -94,6 +92,7 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel,
|
|||||||
|
|
||||||
// For updating account calendars asynchronously.
|
// For updating account calendars asynchronously.
|
||||||
private SemaphoreSlim _accountCalendarUpdateSemaphoreSlim = new(1);
|
private SemaphoreSlim _accountCalendarUpdateSemaphoreSlim = new(1);
|
||||||
|
private bool _runtimeSubscriptionsAttached;
|
||||||
|
|
||||||
public CalendarAppShellViewModel(IPreferencesService preferencesService,
|
public CalendarAppShellViewModel(IPreferencesService preferencesService,
|
||||||
IStatePersistanceService statePersistanceService,
|
IStatePersistanceService statePersistanceService,
|
||||||
@@ -101,25 +100,24 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel,
|
|||||||
ICalendarService calendarService,
|
ICalendarService calendarService,
|
||||||
IAccountCalendarStateService accountCalendarStateService,
|
IAccountCalendarStateService accountCalendarStateService,
|
||||||
INavigationService navigationService,
|
INavigationService navigationService,
|
||||||
|
CalendarPageViewModel calendarPageViewModel,
|
||||||
IMailDialogService dialogService,
|
IMailDialogService dialogService,
|
||||||
IUpdateManager updateManager,
|
IUpdateManager updateManager,
|
||||||
IStoreUpdateService storeUpdateService)
|
IStoreUpdateService storeUpdateService)
|
||||||
{
|
{
|
||||||
_accountService = accountService;
|
_accountService = accountService;
|
||||||
_calendarService = calendarService;
|
_calendarService = calendarService;
|
||||||
|
_calendarPageViewModel = calendarPageViewModel;
|
||||||
_dialogService = dialogService;
|
_dialogService = dialogService;
|
||||||
_updateManager = updateManager;
|
_updateManager = updateManager;
|
||||||
_storeUpdateService = storeUpdateService;
|
_storeUpdateService = storeUpdateService;
|
||||||
|
|
||||||
AccountCalendarStateService = accountCalendarStateService;
|
AccountCalendarStateService = accountCalendarStateService;
|
||||||
AccountCalendarStateService.AccountCalendarSelectionStateChanged += UpdateAccountCalendarRequested;
|
|
||||||
AccountCalendarStateService.CollectiveAccountGroupSelectionStateChanged += AccountCalendarStateCollectivelyChanged;
|
|
||||||
|
|
||||||
NavigationService = navigationService;
|
NavigationService = navigationService;
|
||||||
PreferencesService = preferencesService;
|
PreferencesService = preferencesService;
|
||||||
|
|
||||||
StatePersistenceService = statePersistanceService;
|
StatePersistenceService = statePersistanceService;
|
||||||
StatePersistenceService.StatePropertyChanged += PrefefencesChanged;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDispatcherAssigned()
|
protected override void OnDispatcherAssigned()
|
||||||
@@ -157,9 +155,9 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel,
|
|||||||
public override async void OnNavigatedTo(NavigationMode mode, object parameters)
|
public override async void OnNavigatedTo(NavigationMode mode, object parameters)
|
||||||
{
|
{
|
||||||
base.OnNavigatedTo(mode, parameters);
|
base.OnNavigatedTo(mode, parameters);
|
||||||
|
AttachRuntimeSubscriptions();
|
||||||
|
|
||||||
var activationContext = parameters as ShellModeActivationContext;
|
var activationContext = parameters as ShellModeActivationContext;
|
||||||
var isModeResetActivation = activationContext != null;
|
|
||||||
var shouldRunStartupFlows = activationContext?.IsInitialActivation ?? true;
|
var shouldRunStartupFlows = activationContext?.IsInitialActivation ?? true;
|
||||||
|
|
||||||
PreferencesService.PreferenceChanged -= PreferencesServiceChanged;
|
PreferencesService.PreferenceChanged -= PreferencesServiceChanged;
|
||||||
@@ -167,18 +165,6 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel,
|
|||||||
|
|
||||||
await RefreshFooterItemsAsync(mode == NavigationMode.New);
|
await RefreshFooterItemsAsync(mode == NavigationMode.New);
|
||||||
|
|
||||||
// Preserve the existing calendar shell frame state when the user switches
|
|
||||||
// between Mail and Calendar modes. Back/forward restoration should not
|
|
||||||
// force a new CalendarPage navigation, otherwise pages like
|
|
||||||
// CalendarEventComposePage get dropped from the inner frame stack.
|
|
||||||
if (mode != NavigationMode.New && !isModeResetActivation)
|
|
||||||
{
|
|
||||||
UpdateDateNavigationHeaderItems();
|
|
||||||
await InitializeAccountCalendarsAsync();
|
|
||||||
ValidateConfiguredNewEventCalendar();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateDateNavigationHeaderItems();
|
UpdateDateNavigationHeaderItems();
|
||||||
|
|
||||||
await InitializeAccountCalendarsAsync();
|
await InitializeAccountCalendarsAsync();
|
||||||
@@ -196,7 +182,38 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel,
|
|||||||
{
|
{
|
||||||
base.OnNavigatedFrom(mode, parameters);
|
base.OnNavigatedFrom(mode, parameters);
|
||||||
|
|
||||||
|
DetachRuntimeSubscriptions();
|
||||||
PreferencesService.PreferenceChanged -= PreferencesServiceChanged;
|
PreferencesService.PreferenceChanged -= PreferencesServiceChanged;
|
||||||
|
_ = ExecuteUIThread(() =>
|
||||||
|
{
|
||||||
|
DateNavigationHeaderItems.Clear();
|
||||||
|
AccountCalendarStateService.ClearGroupedAccountCalendars();
|
||||||
|
HighlightedDateRange = null;
|
||||||
|
SelectedDateNavigationHeaderIndex = -1;
|
||||||
|
});
|
||||||
|
_calendarPageViewModel.CleanupForShellDeactivation();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AttachRuntimeSubscriptions()
|
||||||
|
{
|
||||||
|
if (_runtimeSubscriptionsAttached)
|
||||||
|
return;
|
||||||
|
|
||||||
|
AccountCalendarStateService.AccountCalendarSelectionStateChanged += UpdateAccountCalendarRequested;
|
||||||
|
AccountCalendarStateService.CollectiveAccountGroupSelectionStateChanged += AccountCalendarStateCollectivelyChanged;
|
||||||
|
StatePersistenceService.StatePropertyChanged += PrefefencesChanged;
|
||||||
|
_runtimeSubscriptionsAttached = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DetachRuntimeSubscriptions()
|
||||||
|
{
|
||||||
|
if (!_runtimeSubscriptionsAttached)
|
||||||
|
return;
|
||||||
|
|
||||||
|
AccountCalendarStateService.AccountCalendarSelectionStateChanged -= UpdateAccountCalendarRequested;
|
||||||
|
AccountCalendarStateService.CollectiveAccountGroupSelectionStateChanged -= AccountCalendarStateCollectivelyChanged;
|
||||||
|
StatePersistenceService.StatePropertyChanged -= PrefefencesChanged;
|
||||||
|
_runtimeSubscriptionsAttached = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ShowWhatIsNewIfNeededAsync()
|
private async Task ShowWhatIsNewIfNeededAsync()
|
||||||
@@ -346,6 +363,7 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel,
|
|||||||
private DateTime? _navigationDate;
|
private DateTime? _navigationDate;
|
||||||
private readonly IAccountService _accountService;
|
private readonly IAccountService _accountService;
|
||||||
private readonly ICalendarService _calendarService;
|
private readonly ICalendarService _calendarService;
|
||||||
|
private readonly CalendarPageViewModel _calendarPageViewModel;
|
||||||
private readonly IMailDialogService _dialogService;
|
private readonly IMailDialogService _dialogService;
|
||||||
private readonly IUpdateManager _updateManager;
|
private readonly IUpdateManager _updateManager;
|
||||||
private readonly IStoreUpdateService _storeUpdateService;
|
private readonly IStoreUpdateService _storeUpdateService;
|
||||||
@@ -455,7 +473,6 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel,
|
|||||||
|
|
||||||
Messenger.Register<VisibleDateRangeChangedMessage>(this);
|
Messenger.Register<VisibleDateRangeChangedMessage>(this);
|
||||||
Messenger.Register<CalendarEnableStatusChangedMessage>(this);
|
Messenger.Register<CalendarEnableStatusChangedMessage>(this);
|
||||||
Messenger.Register<NavigateManageAccountsRequested>(this);
|
|
||||||
Messenger.Register<CalendarDisplayTypeChangedMessage>(this);
|
Messenger.Register<CalendarDisplayTypeChangedMessage>(this);
|
||||||
Messenger.Register<AccountRemovedMessage>(this);
|
Messenger.Register<AccountRemovedMessage>(this);
|
||||||
}
|
}
|
||||||
@@ -466,7 +483,6 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel,
|
|||||||
|
|
||||||
Messenger.Unregister<VisibleDateRangeChangedMessage>(this);
|
Messenger.Unregister<VisibleDateRangeChangedMessage>(this);
|
||||||
Messenger.Unregister<CalendarEnableStatusChangedMessage>(this);
|
Messenger.Unregister<CalendarEnableStatusChangedMessage>(this);
|
||||||
Messenger.Unregister<NavigateManageAccountsRequested>(this);
|
|
||||||
Messenger.Unregister<CalendarDisplayTypeChangedMessage>(this);
|
Messenger.Unregister<CalendarDisplayTypeChangedMessage>(this);
|
||||||
Messenger.Unregister<AccountRemovedMessage>(this);
|
Messenger.Unregister<AccountRemovedMessage>(this);
|
||||||
}
|
}
|
||||||
@@ -558,8 +574,6 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel,
|
|||||||
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) => NavigationService.Navigate(WinoPage.ManageAccountsPage);
|
|
||||||
|
|
||||||
public void Receive(CalendarDisplayTypeChangedMessage message)
|
public void Receive(CalendarDisplayTypeChangedMessage message)
|
||||||
{
|
{
|
||||||
OnPropertyChanged(nameof(IsVerticalCalendar));
|
OnPropertyChanged(nameof(IsVerticalCalendar));
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using CommunityToolkit.Diagnostics;
|
using CommunityToolkit.Diagnostics;
|
||||||
@@ -20,9 +21,9 @@ using Wino.Core.Domain.Entities.Calendar;
|
|||||||
using Wino.Core.Domain.Enums;
|
using Wino.Core.Domain.Enums;
|
||||||
using Wino.Core.Domain.Extensions;
|
using Wino.Core.Domain.Extensions;
|
||||||
using Wino.Core.Domain.Interfaces;
|
using Wino.Core.Domain.Interfaces;
|
||||||
|
using Wino.Core.Domain.Models;
|
||||||
using Wino.Core.Domain.Models.Calendar;
|
using Wino.Core.Domain.Models.Calendar;
|
||||||
using Wino.Core.Domain.Models.Calendar.CalendarTypeStrategies;
|
using Wino.Core.Domain.Models.Calendar.CalendarTypeStrategies;
|
||||||
using Wino.Core.Domain.Models;
|
|
||||||
using Wino.Core.Domain.Models.Navigation;
|
using Wino.Core.Domain.Models.Navigation;
|
||||||
using Wino.Core.ViewModels;
|
using Wino.Core.ViewModels;
|
||||||
using Wino.Messaging.Client.Calendar;
|
using Wino.Messaging.Client.Calendar;
|
||||||
@@ -37,7 +38,8 @@ public partial class CalendarPageViewModel : CalendarBaseViewModel,
|
|||||||
IRecipient<CalendarItemTappedMessage>,
|
IRecipient<CalendarItemTappedMessage>,
|
||||||
IRecipient<CalendarItemDoubleTappedMessage>,
|
IRecipient<CalendarItemDoubleTappedMessage>,
|
||||||
IRecipient<CalendarItemRightTappedMessage>,
|
IRecipient<CalendarItemRightTappedMessage>,
|
||||||
IRecipient<AccountRemovedMessage>
|
IRecipient<AccountRemovedMessage>,
|
||||||
|
IDisposable
|
||||||
{
|
{
|
||||||
#region Quick Event Creation
|
#region Quick Event Creation
|
||||||
|
|
||||||
@@ -145,6 +147,9 @@ public partial class CalendarPageViewModel : CalendarBaseViewModel,
|
|||||||
|
|
||||||
private SemaphoreSlim _calendarLoadingSemaphore = new(1);
|
private SemaphoreSlim _calendarLoadingSemaphore = new(1);
|
||||||
private bool isLoadMoreBlocked = false;
|
private bool isLoadMoreBlocked = false;
|
||||||
|
private bool _subscriptionsAttached;
|
||||||
|
private CancellationTokenSource _pageLifetimeCts = new();
|
||||||
|
private long _pageLifetimeVersion;
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private CalendarSettings _currentSettings;
|
private CalendarSettings _currentSettings;
|
||||||
@@ -173,11 +178,6 @@ public partial class CalendarPageViewModel : CalendarBaseViewModel,
|
|||||||
_winoRequestDelegator = winoRequestDelegator;
|
_winoRequestDelegator = winoRequestDelegator;
|
||||||
_dialogService = dialogService;
|
_dialogService = dialogService;
|
||||||
|
|
||||||
AccountCalendarStateService.AccountCalendarSelectionStateChanged += UpdateAccountCalendarRequested;
|
|
||||||
AccountCalendarStateService.CollectiveAccountGroupSelectionStateChanged += AccountCalendarStateCollectivelyChanged;
|
|
||||||
|
|
||||||
// We don't register on navigation here. This page is cached.
|
|
||||||
RegisterRecipients();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task KeyboardShortcutHook(KeyboardShortcutTriggerDetails args)
|
public override async Task KeyboardShortcutHook(KeyboardShortcutTriggerDetails args)
|
||||||
@@ -228,15 +228,35 @@ public partial class CalendarPageViewModel : CalendarBaseViewModel,
|
|||||||
Messenger.Register<AccountRemovedMessage>(this);
|
Messenger.Register<AccountRemovedMessage>(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void UnregisterRecipients()
|
||||||
|
{
|
||||||
|
base.UnregisterRecipients();
|
||||||
|
|
||||||
|
Messenger.Unregister<LoadCalendarMessage>(this);
|
||||||
|
Messenger.Unregister<CalendarSettingsUpdatedMessage>(this);
|
||||||
|
Messenger.Unregister<CalendarItemTappedMessage>(this);
|
||||||
|
Messenger.Unregister<CalendarItemDoubleTappedMessage>(this);
|
||||||
|
Messenger.Unregister<CalendarItemRightTappedMessage>(this);
|
||||||
|
Messenger.Unregister<AccountRemovedMessage>(this);
|
||||||
|
}
|
||||||
|
|
||||||
private void AccountCalendarStateCollectivelyChanged(object sender, GroupedAccountCalendarViewModel e)
|
private void AccountCalendarStateCollectivelyChanged(object sender, GroupedAccountCalendarViewModel e)
|
||||||
=> FilterActiveCalendars(DayRanges);
|
=> _ = FilterActiveCalendarsAsync(DayRanges);
|
||||||
|
|
||||||
private void UpdateAccountCalendarRequested(object sender, AccountCalendarViewModel e)
|
private void UpdateAccountCalendarRequested(object sender, AccountCalendarViewModel e)
|
||||||
=> FilterActiveCalendars(DayRanges);
|
=> _ = FilterActiveCalendarsAsync(DayRanges);
|
||||||
|
|
||||||
private async void FilterActiveCalendars(IEnumerable<DayRangeRenderModel> dayRangeRenderModels)
|
private async Task FilterActiveCalendarsAsync(IEnumerable<DayRangeRenderModel> dayRangeRenderModels)
|
||||||
{
|
{
|
||||||
await ExecuteUIThread(() =>
|
await FilterActiveCalendarsAsync(dayRangeRenderModels, CurrentPageLifetimeVersion).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task FilterActiveCalendarsAsync(IEnumerable<DayRangeRenderModel> dayRangeRenderModels, long lifetimeVersion)
|
||||||
|
{
|
||||||
|
if (dayRangeRenderModels == null || !IsPageActive(lifetimeVersion))
|
||||||
|
return;
|
||||||
|
|
||||||
|
await ExecuteUIThreadIfActiveAsync(lifetimeVersion, () =>
|
||||||
{
|
{
|
||||||
var days = dayRangeRenderModels.SelectMany(a => a.CalendarDays);
|
var days = dayRangeRenderModels.SelectMany(a => a.CalendarDays);
|
||||||
|
|
||||||
@@ -269,10 +289,15 @@ public partial class CalendarPageViewModel : CalendarBaseViewModel,
|
|||||||
|
|
||||||
public override void OnNavigatedTo(NavigationMode mode, object parameters)
|
public override void OnNavigatedTo(NavigationMode mode, object parameters)
|
||||||
{
|
{
|
||||||
|
ResetPageLifetime();
|
||||||
|
base.OnNavigatedTo(mode, parameters);
|
||||||
|
AttachSubscriptions();
|
||||||
RefreshSettings();
|
RefreshSettings();
|
||||||
|
IsCalendarEnabled = true;
|
||||||
|
|
||||||
if (mode == NavigationMode.Back)
|
if (mode == NavigationMode.Back && DayRanges.Count > 0)
|
||||||
{
|
{
|
||||||
|
RestoreVisibleState();
|
||||||
_ = RefreshVisibleRangesAsync();
|
_ = RefreshVisibleRangesAsync();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -283,8 +308,197 @@ public partial class CalendarPageViewModel : CalendarBaseViewModel,
|
|||||||
|
|
||||||
public override void OnNavigatedFrom(NavigationMode mode, object parameters)
|
public override void OnNavigatedFrom(NavigationMode mode, object parameters)
|
||||||
{
|
{
|
||||||
// CalendarPage is cached and should continue processing calendar item messages
|
base.OnNavigatedFrom(mode, parameters);
|
||||||
// while details/compose pages are active on top of it.
|
|
||||||
|
if (StatePersistanceService.ApplicationMode == WinoApplicationMode.Calendar)
|
||||||
|
{
|
||||||
|
CancelPendingOperations();
|
||||||
|
DetachSubscriptions();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CleanupForShellDeactivation();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AttachSubscriptions()
|
||||||
|
{
|
||||||
|
if (_subscriptionsAttached)
|
||||||
|
return;
|
||||||
|
|
||||||
|
AccountCalendarStateService.AccountCalendarSelectionStateChanged += UpdateAccountCalendarRequested;
|
||||||
|
AccountCalendarStateService.CollectiveAccountGroupSelectionStateChanged += AccountCalendarStateCollectivelyChanged;
|
||||||
|
_subscriptionsAttached = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DetachSubscriptions()
|
||||||
|
{
|
||||||
|
if (!_subscriptionsAttached)
|
||||||
|
return;
|
||||||
|
|
||||||
|
AccountCalendarStateService.AccountCalendarSelectionStateChanged -= UpdateAccountCalendarRequested;
|
||||||
|
AccountCalendarStateService.CollectiveAccountGroupSelectionStateChanged -= AccountCalendarStateCollectivelyChanged;
|
||||||
|
_subscriptionsAttached = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ReleasePageState()
|
||||||
|
{
|
||||||
|
DetachSubscriptions();
|
||||||
|
|
||||||
|
DisplayDetailsCalendarItemViewModel = null;
|
||||||
|
SelectedQuickEventAccountCalendar = null;
|
||||||
|
SelectedQuickEventDate = null;
|
||||||
|
SelectedDayRange = null;
|
||||||
|
SelectedDateRangeIndex = 0;
|
||||||
|
IsQuickEventDialogOpen = false;
|
||||||
|
DayRanges = [];
|
||||||
|
HourSelectionStrings = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
CleanupForShellDeactivation();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CleanupForShellDeactivation()
|
||||||
|
{
|
||||||
|
CancelPendingOperations();
|
||||||
|
ReleasePageState();
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool RestoreVisibleState()
|
||||||
|
{
|
||||||
|
IsCalendarEnabled = true;
|
||||||
|
|
||||||
|
if (DayRanges.Count == 0)
|
||||||
|
{
|
||||||
|
SelectedDayRange = null;
|
||||||
|
SelectedDateRangeIndex = -1;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var targetIndex = SelectedDateRangeIndex;
|
||||||
|
|
||||||
|
if (SelectedDayRange != null)
|
||||||
|
{
|
||||||
|
var existingSelectedRangeIndex = DayRanges.IndexOf(SelectedDayRange);
|
||||||
|
if (existingSelectedRangeIndex >= 0)
|
||||||
|
{
|
||||||
|
targetIndex = existingSelectedRangeIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetIndex < 0 || targetIndex >= DayRanges.Count)
|
||||||
|
{
|
||||||
|
targetIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SelectedDateRangeIndex = targetIndex;
|
||||||
|
SelectedDayRange = DayRanges[targetIndex];
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DateTime GetRestoreDate()
|
||||||
|
{
|
||||||
|
if (SelectedDayRange != null)
|
||||||
|
{
|
||||||
|
return SelectedDayRange.CalendarRenderOptions.DateRange.StartDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DayRanges.Count == 0)
|
||||||
|
{
|
||||||
|
return DateTime.Now.Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
var targetIndex = SelectedDateRangeIndex;
|
||||||
|
if (targetIndex < 0 || targetIndex >= DayRanges.Count)
|
||||||
|
{
|
||||||
|
targetIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return DayRanges[targetIndex].CalendarRenderOptions.DateRange.StartDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
private long CurrentPageLifetimeVersion => Interlocked.Read(ref _pageLifetimeVersion);
|
||||||
|
|
||||||
|
private bool IsPageActive(long lifetimeVersion)
|
||||||
|
=> lifetimeVersion == CurrentPageLifetimeVersion && !_pageLifetimeCts.IsCancellationRequested;
|
||||||
|
|
||||||
|
private bool IsCurrentPageActive => !_pageLifetimeCts.IsCancellationRequested;
|
||||||
|
|
||||||
|
private void ResetPageLifetime()
|
||||||
|
{
|
||||||
|
CancelPendingOperations();
|
||||||
|
_pageLifetimeCts = new CancellationTokenSource();
|
||||||
|
Interlocked.Increment(ref _pageLifetimeVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CancelPendingOperations()
|
||||||
|
{
|
||||||
|
if (!_pageLifetimeCts.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
_pageLifetimeCts.Cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<bool> WaitForCalendarLoadingLockAsync(long lifetimeVersion)
|
||||||
|
{
|
||||||
|
if (!IsPageActive(lifetimeVersion))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var cancellationToken = _pageLifetimeCts.Token;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await _calendarLoadingSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||||
|
return IsPageActive(lifetimeVersion);
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
catch (ObjectDisposedException)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ReleaseCalendarLoadingLock()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_calendarLoadingSemaphore.Release();
|
||||||
|
}
|
||||||
|
catch (ObjectDisposedException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
catch (SemaphoreFullException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ExecuteUIThreadIfActiveAsync(long lifetimeVersion, Action action)
|
||||||
|
{
|
||||||
|
if (action == null || !IsPageActive(lifetimeVersion))
|
||||||
|
return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await ExecuteUIThread(() =>
|
||||||
|
{
|
||||||
|
if (IsPageActive(lifetimeVersion))
|
||||||
|
{
|
||||||
|
action();
|
||||||
|
}
|
||||||
|
}).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch (COMException) when (!IsPageActive(lifetimeVersion))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
catch (ObjectDisposedException) when (!IsPageActive(lifetimeVersion))
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
@@ -492,21 +706,27 @@ public partial class CalendarPageViewModel : CalendarBaseViewModel,
|
|||||||
|
|
||||||
public async void Receive(LoadCalendarMessage message)
|
public async void Receive(LoadCalendarMessage message)
|
||||||
{
|
{
|
||||||
await _calendarLoadingSemaphore.WaitAsync();
|
var lifetimeVersion = CurrentPageLifetimeVersion;
|
||||||
|
var hasLoadingLock = await WaitForCalendarLoadingLockAsync(lifetimeVersion).ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (!hasLoadingLock)
|
||||||
|
return;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await ExecuteUIThread(() => IsCalendarEnabled = false);
|
await ExecuteUIThreadIfActiveAsync(lifetimeVersion, () => IsCalendarEnabled = false).ConfigureAwait(false);
|
||||||
|
|
||||||
if (ShouldResetDayRanges(message))
|
if (!IsPageActive(lifetimeVersion))
|
||||||
{
|
return;
|
||||||
Debug.WriteLine("Will reset day ranges.");
|
|
||||||
await ClearDayRangeModelsAsync();
|
if (!ShouldResetDayRanges(message) && ShouldScrollToItem(message))
|
||||||
}
|
|
||||||
else if (ShouldScrollToItem(message))
|
|
||||||
{
|
{
|
||||||
// Scroll to the selected date.
|
// Scroll to the selected date.
|
||||||
Messenger.Send(new ScrollToDateMessage(message.DisplayDate));
|
if (IsPageActive(lifetimeVersion))
|
||||||
|
{
|
||||||
|
Messenger.Send(new ScrollToDateMessage(message.DisplayDate));
|
||||||
|
}
|
||||||
|
|
||||||
Debug.WriteLine("Scrolling to selected date.");
|
Debug.WriteLine("Scrolling to selected date.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -516,10 +736,23 @@ public partial class CalendarPageViewModel : CalendarBaseViewModel,
|
|||||||
// This will replace the whole collection because the user initiated a new render.
|
// This will replace the whole collection because the user initiated a new render.
|
||||||
await RenderDatesAsync(message.CalendarInitInitiative,
|
await RenderDatesAsync(message.CalendarInitInitiative,
|
||||||
message.DisplayDate,
|
message.DisplayDate,
|
||||||
CalendarLoadDirection.Replace);
|
CalendarLoadDirection.Replace,
|
||||||
|
lifetimeVersion).ConfigureAwait(false);
|
||||||
|
|
||||||
// Scroll to the current hour.
|
// Scroll to the current hour.
|
||||||
Messenger.Send(new ScrollToHourMessage(TimeSpan.FromHours(DateTime.Now.Hour)));
|
if (IsPageActive(lifetimeVersion))
|
||||||
|
{
|
||||||
|
Messenger.Send(new ScrollToHourMessage(TimeSpan.FromHours(DateTime.Now.Hour)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
catch (COMException) when (!IsPageActive(lifetimeVersion))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
catch (ObjectDisposedException) when (!IsPageActive(lifetimeVersion))
|
||||||
|
{
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -528,55 +761,88 @@ public partial class CalendarPageViewModel : CalendarBaseViewModel,
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
_calendarLoadingSemaphore.Release();
|
ReleaseCalendarLoadingLock();
|
||||||
|
|
||||||
await ExecuteUIThread(() => IsCalendarEnabled = true);
|
await ExecuteUIThreadIfActiveAsync(lifetimeVersion, () => IsCalendarEnabled = true).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private async Task AddDayRangeModelAsync(DayRangeRenderModel dayRangeRenderModel)
|
private async Task AddDayRangeModelAsync(DayRangeRenderModel dayRangeRenderModel, long lifetimeVersion)
|
||||||
{
|
{
|
||||||
if (dayRangeRenderModel == null) return;
|
if (dayRangeRenderModel == null) return;
|
||||||
|
|
||||||
await ExecuteUIThread(() =>
|
await ExecuteUIThreadIfActiveAsync(lifetimeVersion, () =>
|
||||||
{
|
{
|
||||||
DayRanges.Add(dayRangeRenderModel);
|
DayRanges.Add(dayRangeRenderModel);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task InsertDayRangeModelAsync(DayRangeRenderModel dayRangeRenderModel, int index)
|
private async Task InsertDayRangeModelAsync(DayRangeRenderModel dayRangeRenderModel, int index, long lifetimeVersion)
|
||||||
{
|
{
|
||||||
if (dayRangeRenderModel == null) return;
|
if (dayRangeRenderModel == null) return;
|
||||||
|
|
||||||
await ExecuteUIThread(() =>
|
await ExecuteUIThreadIfActiveAsync(lifetimeVersion, () =>
|
||||||
{
|
{
|
||||||
DayRanges.Insert(index, dayRangeRenderModel);
|
DayRanges.Insert(index, dayRangeRenderModel);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task RemoveDayRangeModelAsync(DayRangeRenderModel dayRangeRenderModel)
|
private async Task RemoveDayRangeModelAsync(DayRangeRenderModel dayRangeRenderModel, long lifetimeVersion)
|
||||||
{
|
{
|
||||||
if (dayRangeRenderModel == null) return;
|
if (dayRangeRenderModel == null) return;
|
||||||
|
|
||||||
await ExecuteUIThread(() =>
|
await ExecuteUIThreadIfActiveAsync(lifetimeVersion, () =>
|
||||||
{
|
{
|
||||||
DayRanges.Remove(dayRangeRenderModel);
|
DayRanges.Remove(dayRangeRenderModel);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ClearDayRangeModelsAsync()
|
private async Task ClearDayRangeModelsAsync(long lifetimeVersion)
|
||||||
{
|
{
|
||||||
await ExecuteUIThread(() =>
|
await ExecuteUIThreadIfActiveAsync(lifetimeVersion, () =>
|
||||||
{
|
{
|
||||||
DayRanges.Clear();
|
DayRanges.Clear();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task ReplaceDayRangeModelsAsync(IEnumerable<DayRangeRenderModel> dayRangeRenderModels, DateTime displayDate, long lifetimeVersion)
|
||||||
|
{
|
||||||
|
var renderModels = dayRangeRenderModels?.ToList() ?? [];
|
||||||
|
|
||||||
|
await ExecuteUIThreadIfActiveAsync(lifetimeVersion, () =>
|
||||||
|
{
|
||||||
|
DayRanges.ReplaceRange(renderModels);
|
||||||
|
|
||||||
|
if (renderModels.Count == 0)
|
||||||
|
{
|
||||||
|
SelectedDayRange = null;
|
||||||
|
SelectedDateRangeIndex = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var selectedIndex = renderModels.FindIndex(model =>
|
||||||
|
displayDate >= model.CalendarRenderOptions.DateRange.StartDate &&
|
||||||
|
displayDate <= model.CalendarRenderOptions.DateRange.EndDate);
|
||||||
|
|
||||||
|
if (selectedIndex < 0)
|
||||||
|
{
|
||||||
|
selectedIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SelectedDateRangeIndex = selectedIndex;
|
||||||
|
SelectedDayRange = renderModels[selectedIndex];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private async Task RenderDatesAsync(CalendarInitInitiative calendarInitInitiative,
|
private async Task RenderDatesAsync(CalendarInitInitiative calendarInitInitiative,
|
||||||
DateTime? loadingDisplayDate = null,
|
DateTime? loadingDisplayDate = null,
|
||||||
CalendarLoadDirection calendarLoadDirection = CalendarLoadDirection.Replace)
|
CalendarLoadDirection calendarLoadDirection = CalendarLoadDirection.Replace,
|
||||||
|
long lifetimeVersion = 0)
|
||||||
{
|
{
|
||||||
|
if (!IsPageActive(lifetimeVersion))
|
||||||
|
return;
|
||||||
|
|
||||||
isLoadMoreBlocked = calendarLoadDirection == CalendarLoadDirection.Replace;
|
isLoadMoreBlocked = calendarLoadDirection == CalendarLoadDirection.Replace;
|
||||||
|
|
||||||
// This is the part we arrange the flip view calendar logic.
|
// This is the part we arrange the flip view calendar logic.
|
||||||
@@ -643,11 +909,17 @@ public partial class CalendarPageViewModel : CalendarBaseViewModel,
|
|||||||
// Dates are loaded. Now load the events for them.
|
// Dates are loaded. Now load the events for them.
|
||||||
foreach (var renderModel in renderModels)
|
foreach (var renderModel in renderModels)
|
||||||
{
|
{
|
||||||
await InitializeCalendarEventsForDayRangeAsync(renderModel).ConfigureAwait(false);
|
await InitializeCalendarEventsForDayRangeAsync(renderModel, lifetimeVersion).ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (!IsPageActive(lifetimeVersion))
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter by active calendars. This is a quick operation, and things are not on the UI yet.
|
// Filter by active calendars. This is a quick operation, and things are not on the UI yet.
|
||||||
FilterActiveCalendars(renderModels);
|
await FilterActiveCalendarsAsync(renderModels, lifetimeVersion).ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (!IsPageActive(lifetimeVersion))
|
||||||
|
return;
|
||||||
|
|
||||||
CalendarLoadDirection animationDirection = calendarLoadDirection;
|
CalendarLoadDirection animationDirection = calendarLoadDirection;
|
||||||
|
|
||||||
@@ -655,29 +927,26 @@ public partial class CalendarPageViewModel : CalendarBaseViewModel,
|
|||||||
|
|
||||||
if (calendarLoadDirection == CalendarLoadDirection.Replace)
|
if (calendarLoadDirection == CalendarLoadDirection.Replace)
|
||||||
{
|
{
|
||||||
// New date ranges are being replaced.
|
|
||||||
// We must preserve existing selection if any, add the items before/after the current one, remove the current one.
|
|
||||||
// This will make sure the new dates are animated in the correct direction.
|
|
||||||
|
|
||||||
isLoadMoreBlocked = true;
|
isLoadMoreBlocked = true;
|
||||||
|
await ReplaceDayRangeModelsAsync(renderModels, displayDate, lifetimeVersion).ConfigureAwait(false);
|
||||||
|
isLoadMoreBlocked = false;
|
||||||
|
|
||||||
// Remove all other dates except this one.
|
if (calendarInitInitiative == CalendarInitInitiative.User)
|
||||||
var rangesToRemove = DayRanges.Where(a => a != SelectedDayRange).ToList();
|
|
||||||
|
|
||||||
foreach (var range in rangesToRemove)
|
|
||||||
{
|
{
|
||||||
await RemoveDayRangeModelAsync(range);
|
_currentDisplayType = StatePersistanceService.CalendarDisplayType;
|
||||||
|
_displayDayCount = StatePersistanceService.DayDisplayCount;
|
||||||
|
|
||||||
|
Messenger.Send(new ScrollToDateMessage(displayDate));
|
||||||
}
|
}
|
||||||
|
|
||||||
animationDirection = displayDate <= SelectedDayRange?.CalendarRenderOptions.DateRange.StartDate ?
|
return;
|
||||||
CalendarLoadDirection.Previous : CalendarLoadDirection.Next;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (animationDirection == CalendarLoadDirection.Next)
|
if (animationDirection == CalendarLoadDirection.Next)
|
||||||
{
|
{
|
||||||
foreach (var item in renderModels)
|
foreach (var item in renderModels)
|
||||||
{
|
{
|
||||||
await AddDayRangeModelAsync(item);
|
await AddDayRangeModelAsync(item, lifetimeVersion);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (animationDirection == CalendarLoadDirection.Previous)
|
else if (animationDirection == CalendarLoadDirection.Previous)
|
||||||
@@ -690,7 +959,7 @@ public partial class CalendarPageViewModel : CalendarBaseViewModel,
|
|||||||
// Insert each render model in reverse order.
|
// Insert each render model in reverse order.
|
||||||
for (int i = renderModels.Count - 1; i >= 0; i--)
|
for (int i = renderModels.Count - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
await InsertDayRangeModelAsync(renderModels[i], 0);
|
await InsertDayRangeModelAsync(renderModels[i], 0, lifetimeVersion);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -723,12 +992,15 @@ public partial class CalendarPageViewModel : CalendarBaseViewModel,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task InitializeCalendarEventsForDayRangeAsync(DayRangeRenderModel dayRangeRenderModel)
|
private async Task InitializeCalendarEventsForDayRangeAsync(DayRangeRenderModel dayRangeRenderModel, long lifetimeVersion)
|
||||||
{
|
{
|
||||||
|
if (!IsPageActive(lifetimeVersion))
|
||||||
|
return;
|
||||||
|
|
||||||
// Clear all events first for all days.
|
// Clear all events first for all days.
|
||||||
foreach (var day in dayRangeRenderModel.CalendarDays)
|
foreach (var day in dayRangeRenderModel.CalendarDays)
|
||||||
{
|
{
|
||||||
await ExecuteUIThread(() =>
|
await ExecuteUIThreadIfActiveAsync(lifetimeVersion, () =>
|
||||||
{
|
{
|
||||||
day.EventsCollection.Clear();
|
day.EventsCollection.Clear();
|
||||||
});
|
});
|
||||||
@@ -739,6 +1011,9 @@ public partial class CalendarPageViewModel : CalendarBaseViewModel,
|
|||||||
|
|
||||||
foreach (var calendarViewModel in AccountCalendarStateService.AllCalendars)
|
foreach (var calendarViewModel in AccountCalendarStateService.AllCalendars)
|
||||||
{
|
{
|
||||||
|
if (!IsPageActive(lifetimeVersion))
|
||||||
|
return;
|
||||||
|
|
||||||
// Check all the events for the given date range and calendar.
|
// Check all the events for the given date range and calendar.
|
||||||
// Then find the day representation for all the events returned, and add to the collection.
|
// Then find the day representation for all the events returned, and add to the collection.
|
||||||
|
|
||||||
@@ -746,13 +1021,16 @@ public partial class CalendarPageViewModel : CalendarBaseViewModel,
|
|||||||
|
|
||||||
foreach (var @event in events)
|
foreach (var @event in events)
|
||||||
{
|
{
|
||||||
|
if (!IsPageActive(lifetimeVersion))
|
||||||
|
return;
|
||||||
|
|
||||||
// Find the days that the event falls into.
|
// Find the days that the event falls into.
|
||||||
var allDaysForEvent = dayRangeRenderModel.CalendarDays.Where(a => a.Period.OverlapsWith(@event.Period));
|
var allDaysForEvent = dayRangeRenderModel.CalendarDays.Where(a => a.Period.OverlapsWith(@event.Period));
|
||||||
|
|
||||||
foreach (var calendarDay in allDaysForEvent)
|
foreach (var calendarDay in allDaysForEvent)
|
||||||
{
|
{
|
||||||
var calendarItemViewModel = new CalendarItemViewModel(@event);
|
var calendarItemViewModel = new CalendarItemViewModel(@event);
|
||||||
await ExecuteUIThread(() =>
|
await ExecuteUIThreadIfActiveAsync(lifetimeVersion, () =>
|
||||||
{
|
{
|
||||||
calendarDay.EventsCollection.AddCalendarItem(calendarItemViewModel);
|
calendarDay.EventsCollection.AddCalendarItem(calendarItemViewModel);
|
||||||
});
|
});
|
||||||
@@ -763,21 +1041,33 @@ public partial class CalendarPageViewModel : CalendarBaseViewModel,
|
|||||||
|
|
||||||
private async Task RefreshVisibleRangesAsync()
|
private async Task RefreshVisibleRangesAsync()
|
||||||
{
|
{
|
||||||
|
var lifetimeVersion = CurrentPageLifetimeVersion;
|
||||||
|
var hasLoadingLock = false;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await _calendarLoadingSemaphore.WaitAsync().ConfigureAwait(false);
|
hasLoadingLock = await WaitForCalendarLoadingLockAsync(lifetimeVersion).ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (!hasLoadingLock)
|
||||||
|
return;
|
||||||
|
|
||||||
if (DayRanges == null || DayRanges.Count == 0)
|
if (DayRanges == null || DayRanges.Count == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
RefreshSettings();
|
RefreshSettings();
|
||||||
|
await RenderDatesAsync(CalendarInitInitiative.User,
|
||||||
foreach (var dayRange in DayRanges)
|
GetRestoreDate(),
|
||||||
{
|
CalendarLoadDirection.Replace,
|
||||||
await InitializeCalendarEventsForDayRangeAsync(dayRange).ConfigureAwait(false);
|
lifetimeVersion).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
catch (OperationCanceledException)
|
||||||
FilterActiveCalendars(DayRanges);
|
{
|
||||||
|
}
|
||||||
|
catch (COMException) when (!IsPageActive(lifetimeVersion))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
catch (ObjectDisposedException) when (!IsPageActive(lifetimeVersion))
|
||||||
|
{
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -785,7 +1075,10 @@ public partial class CalendarPageViewModel : CalendarBaseViewModel,
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
_calendarLoadingSemaphore.Release();
|
if (hasLoadingLock)
|
||||||
|
{
|
||||||
|
ReleaseCalendarLoadingLock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -891,9 +1184,15 @@ public partial class CalendarPageViewModel : CalendarBaseViewModel,
|
|||||||
|
|
||||||
private async Task LoadMoreAsync()
|
private async Task LoadMoreAsync()
|
||||||
{
|
{
|
||||||
|
var lifetimeVersion = CurrentPageLifetimeVersion;
|
||||||
|
var hasLoadingLock = false;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await _calendarLoadingSemaphore.WaitAsync();
|
hasLoadingLock = await WaitForCalendarLoadingLockAsync(lifetimeVersion).ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (!hasLoadingLock)
|
||||||
|
return;
|
||||||
|
|
||||||
// Depending on the selected index, we'll load more dates.
|
// Depending on the selected index, we'll load more dates.
|
||||||
// Day ranges may change while the async update is in progress.
|
// Day ranges may change while the async update is in progress.
|
||||||
@@ -902,20 +1201,33 @@ public partial class CalendarPageViewModel : CalendarBaseViewModel,
|
|||||||
|
|
||||||
if (SelectedDateRangeIndex == 0)
|
if (SelectedDateRangeIndex == 0)
|
||||||
{
|
{
|
||||||
await RenderDatesAsync(CalendarInitInitiative.App, calendarLoadDirection: CalendarLoadDirection.Previous);
|
await RenderDatesAsync(CalendarInitInitiative.App, calendarLoadDirection: CalendarLoadDirection.Previous, lifetimeVersion: lifetimeVersion);
|
||||||
}
|
}
|
||||||
else if (SelectedDateRangeIndex == DayRanges.Count - 1)
|
else if (SelectedDateRangeIndex == DayRanges.Count - 1)
|
||||||
{
|
{
|
||||||
await RenderDatesAsync(CalendarInitInitiative.App, calendarLoadDirection: CalendarLoadDirection.Next);
|
await RenderDatesAsync(CalendarInitInitiative.App, calendarLoadDirection: CalendarLoadDirection.Next, lifetimeVersion: lifetimeVersion);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (OperationCanceledException)
|
||||||
{
|
{
|
||||||
|
}
|
||||||
|
catch (COMException) when (!IsPageActive(lifetimeVersion))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
catch (ObjectDisposedException) when (!IsPageActive(lifetimeVersion))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Debug.WriteLine(ex);
|
||||||
Debugger.Break();
|
Debugger.Break();
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
_calendarLoadingSemaphore.Release();
|
if (hasLoadingLock)
|
||||||
|
{
|
||||||
|
ReleaseCalendarLoadingLock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1042,9 +1354,14 @@ public partial class CalendarPageViewModel : CalendarBaseViewModel,
|
|||||||
|
|
||||||
public async void Receive(AccountRemovedMessage message)
|
public async void Receive(AccountRemovedMessage message)
|
||||||
{
|
{
|
||||||
|
var lifetimeVersion = CurrentPageLifetimeVersion;
|
||||||
|
|
||||||
|
if (!IsPageActive(lifetimeVersion))
|
||||||
|
return;
|
||||||
|
|
||||||
var removedAccountId = message.Account.Id;
|
var removedAccountId = message.Account.Id;
|
||||||
|
|
||||||
await ExecuteUIThread(() =>
|
await ExecuteUIThreadIfActiveAsync(lifetimeVersion, () =>
|
||||||
{
|
{
|
||||||
foreach (var dayRange in DayRanges)
|
foreach (var dayRange in DayRanges)
|
||||||
{
|
{
|
||||||
@@ -1066,6 +1383,7 @@ public partial class CalendarPageViewModel : CalendarBaseViewModel,
|
|||||||
protected override async void OnCalendarItemDeleted(CalendarItem calendarItem)
|
protected override async void OnCalendarItemDeleted(CalendarItem calendarItem)
|
||||||
{
|
{
|
||||||
base.OnCalendarItemDeleted(calendarItem);
|
base.OnCalendarItemDeleted(calendarItem);
|
||||||
|
var lifetimeVersion = CurrentPageLifetimeVersion;
|
||||||
|
|
||||||
Debug.WriteLine($"Calendar item deleted: {calendarItem.Id}");
|
Debug.WriteLine($"Calendar item deleted: {calendarItem.Id}");
|
||||||
|
|
||||||
@@ -1080,7 +1398,7 @@ public partial class CalendarPageViewModel : CalendarBaseViewModel,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Remove the event and its occurrences from all visible date ranges.
|
// Remove the event and its occurrences from all visible date ranges.
|
||||||
await ExecuteUIThread(() =>
|
await ExecuteUIThreadIfActiveAsync(lifetimeVersion, () =>
|
||||||
{
|
{
|
||||||
foreach (var dayRange in DayRanges)
|
foreach (var dayRange in DayRanges)
|
||||||
{
|
{
|
||||||
@@ -1097,6 +1415,7 @@ public partial class CalendarPageViewModel : CalendarBaseViewModel,
|
|||||||
protected override async void OnCalendarItemUpdated(CalendarItem calendarItem, CalendarItemUpdateSource source)
|
protected override async void OnCalendarItemUpdated(CalendarItem calendarItem, CalendarItemUpdateSource source)
|
||||||
{
|
{
|
||||||
base.OnCalendarItemUpdated(calendarItem, source);
|
base.OnCalendarItemUpdated(calendarItem, source);
|
||||||
|
var lifetimeVersion = CurrentPageLifetimeVersion;
|
||||||
Debug.WriteLine($"Calendar item updated: {calendarItem.Id}");
|
Debug.WriteLine($"Calendar item updated: {calendarItem.Id}");
|
||||||
|
|
||||||
// Local-only calendar operations are persisted immediately without real network I/O.
|
// Local-only calendar operations are persisted immediately without real network I/O.
|
||||||
@@ -1128,7 +1447,7 @@ public partial class CalendarPageViewModel : CalendarBaseViewModel,
|
|||||||
.Where(a => a.Period.OverlapsWith(calendarItem.Period))
|
.Where(a => a.Period.OverlapsWith(calendarItem.Period))
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
await ExecuteUIThread(() =>
|
await ExecuteUIThreadIfActiveAsync(lifetimeVersion, () =>
|
||||||
{
|
{
|
||||||
if (source == CalendarItemUpdateSource.ClientUpdated)
|
if (source == CalendarItemUpdateSource.ClientUpdated)
|
||||||
{
|
{
|
||||||
@@ -1178,12 +1497,13 @@ public partial class CalendarPageViewModel : CalendarBaseViewModel,
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
FilterActiveCalendars(DayRanges);
|
await FilterActiveCalendarsAsync(DayRanges).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async void OnCalendarItemAdded(CalendarItem calendarItem)
|
protected override async void OnCalendarItemAdded(CalendarItem calendarItem)
|
||||||
{
|
{
|
||||||
base.OnCalendarItemAdded(calendarItem);
|
base.OnCalendarItemAdded(calendarItem);
|
||||||
|
var lifetimeVersion = CurrentPageLifetimeVersion;
|
||||||
Debug.WriteLine($"Calendar item added: {calendarItem.Id}");
|
Debug.WriteLine($"Calendar item added: {calendarItem.Id}");
|
||||||
|
|
||||||
// Series master events should not be visible on the UI.
|
// Series master events should not be visible on the UI.
|
||||||
@@ -1209,7 +1529,7 @@ public partial class CalendarPageViewModel : CalendarBaseViewModel,
|
|||||||
{
|
{
|
||||||
Debug.WriteLine($"Mapped pending busy item {pendingMatch.Id} with synced server event {calendarItem.Id}.");
|
Debug.WriteLine($"Mapped pending busy item {pendingMatch.Id} with synced server event {calendarItem.Id}.");
|
||||||
|
|
||||||
await ExecuteUIThread(() =>
|
await ExecuteUIThreadIfActiveAsync(lifetimeVersion, () =>
|
||||||
{
|
{
|
||||||
RemoveCalendarItemEverywhere(pendingMatch.Id);
|
RemoveCalendarItemEverywhere(pendingMatch.Id);
|
||||||
});
|
});
|
||||||
@@ -1230,17 +1550,19 @@ public partial class CalendarPageViewModel : CalendarBaseViewModel,
|
|||||||
IsBusy = string.IsNullOrEmpty(calendarItem.RemoteEventId)
|
IsBusy = string.IsNullOrEmpty(calendarItem.RemoteEventId)
|
||||||
};
|
};
|
||||||
|
|
||||||
await ExecuteUIThread(() =>
|
await ExecuteUIThreadIfActiveAsync(lifetimeVersion, () =>
|
||||||
{
|
{
|
||||||
calendarDay.EventsCollection.AddCalendarItem(calendarItemViewModel);
|
calendarDay.EventsCollection.AddCalendarItem(calendarItemViewModel);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
FilterActiveCalendars(DayRanges);
|
await FilterActiveCalendarsAsync(DayRanges).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task RestoreVisibleRecurringSeriesInstancesAsync(CalendarItem recurringParent)
|
private async Task RestoreVisibleRecurringSeriesInstancesAsync(CalendarItem recurringParent)
|
||||||
{
|
{
|
||||||
|
var lifetimeVersion = CurrentPageLifetimeVersion;
|
||||||
|
|
||||||
if (DayRanges.DisplayRange == null || recurringParent?.AssignedCalendar == null)
|
if (DayRanges.DisplayRange == null || recurringParent?.AssignedCalendar == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -1254,7 +1576,7 @@ public partial class CalendarPageViewModel : CalendarBaseViewModel,
|
|||||||
if (!recurringChildren.Any())
|
if (!recurringChildren.Any())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
await ExecuteUIThread(() =>
|
await ExecuteUIThreadIfActiveAsync(lifetimeVersion, () =>
|
||||||
{
|
{
|
||||||
foreach (var child in recurringChildren)
|
foreach (var child in recurringChildren)
|
||||||
{
|
{
|
||||||
@@ -1277,6 +1599,6 @@ public partial class CalendarPageViewModel : CalendarBaseViewModel,
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
FilterActiveCalendars(DayRanges);
|
await FilterActiveCalendarsAsync(DayRanges).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,5 +69,5 @@ public interface IShellHost
|
|||||||
{
|
{
|
||||||
bool HasShellContent { get; }
|
bool HasShellContent { get; }
|
||||||
|
|
||||||
void ActivateMode(WinoApplicationMode mode, bool isInitialActivation);
|
void ActivateMode(WinoApplicationMode mode, ShellModeActivationContext activationContext);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,22 +58,14 @@ public partial class SettingOptionsPageViewModel : CoreBaseViewModel
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[RelayCommand]
|
|
||||||
private void GoAccountSettings() => Messenger.Send<NavigateManageAccountsRequested>();
|
|
||||||
|
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
public void NavigateSubDetail(object type)
|
public void NavigateSubDetail(object type)
|
||||||
{
|
{
|
||||||
if (type is WinoPage pageType)
|
if (type is WinoPage pageType)
|
||||||
{
|
{
|
||||||
if (pageType == WinoPage.AccountManagementPage)
|
|
||||||
{
|
|
||||||
GoAccountSettings();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
string pageTitle = pageType switch
|
string pageTitle = pageType switch
|
||||||
{
|
{
|
||||||
|
WinoPage.ManageAccountsPage => Translator.SettingsManageAccountSettings_Title,
|
||||||
WinoPage.PersonalizationPage => Translator.SettingsPersonalization_Title,
|
WinoPage.PersonalizationPage => Translator.SettingsPersonalization_Title,
|
||||||
WinoPage.AboutPage => Translator.SettingsAbout_Title,
|
WinoPage.AboutPage => Translator.SettingsAbout_Title,
|
||||||
WinoPage.MessageListPage => Translator.SettingsMessageList_Title,
|
WinoPage.MessageListPage => Translator.SettingsMessageList_Title,
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ namespace Wino.Mail.ViewModels;
|
|||||||
|
|
||||||
public partial class MailAppShellViewModel : MailBaseViewModel,
|
public partial class MailAppShellViewModel : MailBaseViewModel,
|
||||||
IMailShellClient,
|
IMailShellClient,
|
||||||
IRecipient<NavigateManageAccountsRequested>,
|
|
||||||
IRecipient<MailtoProtocolMessageRequested>,
|
IRecipient<MailtoProtocolMessageRequested>,
|
||||||
IRecipient<RefreshUnreadCountsMessage>,
|
IRecipient<RefreshUnreadCountsMessage>,
|
||||||
IRecipient<AccountsMenuRefreshRequested>,
|
IRecipient<AccountsMenuRefreshRequested>,
|
||||||
@@ -232,31 +231,19 @@ public partial class MailAppShellViewModel : MailBaseViewModel,
|
|||||||
base.OnNavigatedTo(mode, parameters);
|
base.OnNavigatedTo(mode, parameters);
|
||||||
|
|
||||||
var activationContext = parameters as ShellModeActivationContext;
|
var activationContext = parameters as ShellModeActivationContext;
|
||||||
var isModeResetActivation = activationContext != null;
|
|
||||||
var shouldRunStartupFlows = activationContext?.IsInitialActivation ?? true;
|
var shouldRunStartupFlows = activationContext?.IsInitialActivation ?? true;
|
||||||
|
var hasExistingMenuItems = MenuItems?.Any() == true;
|
||||||
|
|
||||||
PreferencesService.PreferenceChanged -= PreferencesServiceChanged;
|
PreferencesService.PreferenceChanged -= PreferencesServiceChanged;
|
||||||
PreferencesService.PreferenceChanged += PreferencesServiceChanged;
|
PreferencesService.PreferenceChanged += PreferencesServiceChanged;
|
||||||
|
|
||||||
if (mode == NavigationMode.Back && !isModeResetActivation)
|
|
||||||
{
|
|
||||||
// Preserve current mail/folder selection and active rendering page when
|
|
||||||
// switching back from Calendar mode. Recreating menu/folder state here
|
|
||||||
// causes a folder reload, which clears selection and disposes reader page.
|
|
||||||
// Rehydrate only if menu state is unexpectedly empty.
|
|
||||||
if (MenuItems?.Any() != true || FooterItems?.Any() != true)
|
|
||||||
{
|
|
||||||
await CreateFooterItemsAsync();
|
|
||||||
await RecreateMenuItemsAsync();
|
|
||||||
await RestoreSelectedAccountAfterMenuRefreshAsync(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await CreateFooterItemsAsync(true);
|
await CreateFooterItemsAsync(true);
|
||||||
|
|
||||||
await RecreateMenuItemsAsync();
|
if (!hasExistingMenuItems)
|
||||||
|
{
|
||||||
|
await RecreateMenuItemsAsync();
|
||||||
|
}
|
||||||
|
|
||||||
await ProcessLaunchOptionsAsync();
|
await ProcessLaunchOptionsAsync();
|
||||||
await ValidateWebView2RuntimeAsync();
|
await ValidateWebView2RuntimeAsync();
|
||||||
|
|
||||||
@@ -934,8 +921,6 @@ public partial class MailAppShellViewModel : MailBaseViewModel,
|
|||||||
accountMenuItem.UpdateAccount(accountModel);
|
accountMenuItem.UpdateAccount(accountModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Receive(NavigateManageAccountsRequested message) => SelectedMenuItem = ManageAccountsMenuItem;
|
|
||||||
|
|
||||||
public async void Receive(MailtoProtocolMessageRequested message)
|
public async void Receive(MailtoProtocolMessageRequested message)
|
||||||
{
|
{
|
||||||
var accounts = await _accountService.GetAccountsAsync();
|
var accounts = await _accountService.GetAccountsAsync();
|
||||||
@@ -1173,7 +1158,6 @@ public partial class MailAppShellViewModel : MailBaseViewModel,
|
|||||||
Messenger.Register<AccountCreatedMessage>(this);
|
Messenger.Register<AccountCreatedMessage>(this);
|
||||||
Messenger.Register<AccountRemovedMessage>(this);
|
Messenger.Register<AccountRemovedMessage>(this);
|
||||||
Messenger.Register<AccountUpdatedMessage>(this);
|
Messenger.Register<AccountUpdatedMessage>(this);
|
||||||
Messenger.Register<NavigateManageAccountsRequested>(this);
|
|
||||||
Messenger.Register<MailtoProtocolMessageRequested>(this);
|
Messenger.Register<MailtoProtocolMessageRequested>(this);
|
||||||
Messenger.Register<RefreshUnreadCountsMessage>(this);
|
Messenger.Register<RefreshUnreadCountsMessage>(this);
|
||||||
Messenger.Register<AccountsMenuRefreshRequested>(this);
|
Messenger.Register<AccountsMenuRefreshRequested>(this);
|
||||||
@@ -1192,7 +1176,6 @@ public partial class MailAppShellViewModel : MailBaseViewModel,
|
|||||||
Messenger.Unregister<AccountCreatedMessage>(this);
|
Messenger.Unregister<AccountCreatedMessage>(this);
|
||||||
Messenger.Unregister<AccountRemovedMessage>(this);
|
Messenger.Unregister<AccountRemovedMessage>(this);
|
||||||
Messenger.Unregister<AccountUpdatedMessage>(this);
|
Messenger.Unregister<AccountUpdatedMessage>(this);
|
||||||
Messenger.Unregister<NavigateManageAccountsRequested>(this);
|
|
||||||
Messenger.Unregister<MailtoProtocolMessageRequested>(this);
|
Messenger.Unregister<MailtoProtocolMessageRequested>(this);
|
||||||
Messenger.Unregister<RefreshUnreadCountsMessage>(this);
|
Messenger.Unregister<RefreshUnreadCountsMessage>(this);
|
||||||
Messenger.Unregister<AccountsMenuRefreshRequested>(this);
|
Messenger.Unregister<AccountsMenuRefreshRequested>(this);
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ using Wino.Core.Domain.Entities.Mail;
|
|||||||
using Wino.Core.Domain.Entities.Shared;
|
using Wino.Core.Domain.Entities.Shared;
|
||||||
using Wino.Core.Domain.Enums;
|
using Wino.Core.Domain.Enums;
|
||||||
using Wino.Core.Domain.Interfaces;
|
using Wino.Core.Domain.Interfaces;
|
||||||
using Wino.Core.Domain.Models.Folders;
|
|
||||||
using Wino.Core.Domain.Models;
|
using Wino.Core.Domain.Models;
|
||||||
|
using Wino.Core.Domain.Models.Folders;
|
||||||
using Wino.Core.Domain.Models.MailItem;
|
using Wino.Core.Domain.Models.MailItem;
|
||||||
using Wino.Core.Domain.Models.Menus;
|
using Wino.Core.Domain.Models.Menus;
|
||||||
using Wino.Core.Domain.Models.Navigation;
|
using Wino.Core.Domain.Models.Navigation;
|
||||||
@@ -198,30 +198,6 @@ public partial class MailListPageViewModel : MailBaseViewModel,
|
|||||||
SelectedSortingOption = SortingOptions[0];
|
SelectedSortingOption = SortingOptions[0];
|
||||||
|
|
||||||
MailListLength = statePersistenceService.MailListPaneLength;
|
MailListLength = statePersistenceService.MailListPaneLength;
|
||||||
|
|
||||||
//_selectionChangedThrottler = new ThrottledEventHandler(100, () =>
|
|
||||||
//{
|
|
||||||
// _ = ExecuteUIThread(() =>
|
|
||||||
// {
|
|
||||||
// if (MailCollection.SelectedVisibleCount == 1)
|
|
||||||
// {
|
|
||||||
// ActiveMailItemChanged(MailCollection.SelectedVisibleItems.ElementAt(0));
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// // At this point, either we don't have any item selected
|
|
||||||
// // or we have multiple item selected. In either case
|
|
||||||
// // there should be no active item.
|
|
||||||
|
|
||||||
// ActiveMailItemChanged(null);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// NotifyItemSelected();
|
|
||||||
// SetupTopBarActions();
|
|
||||||
// });
|
|
||||||
|
|
||||||
// ThrottledSelectionChanged?.Invoke(this, EventArgs.Empty);
|
|
||||||
//});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnNavigatedTo(NavigationMode mode, object parameters)
|
public override void OnNavigatedTo(NavigationMode mode, object parameters)
|
||||||
|
|||||||
@@ -177,7 +177,7 @@ public partial class App : WinoApplication,
|
|||||||
services.AddTransient(typeof(SignatureAndEncryptionPageViewModel));
|
services.AddTransient(typeof(SignatureAndEncryptionPageViewModel));
|
||||||
services.AddTransient(typeof(EmailTemplatesPageViewModel));
|
services.AddTransient(typeof(EmailTemplatesPageViewModel));
|
||||||
services.AddTransient(typeof(CreateEmailTemplatePageViewModel));
|
services.AddTransient(typeof(CreateEmailTemplatePageViewModel));
|
||||||
services.AddTransient(typeof(CalendarPageViewModel));
|
services.AddSingleton(typeof(CalendarPageViewModel));
|
||||||
services.AddTransient(typeof(CalendarSettingsPageViewModel));
|
services.AddTransient(typeof(CalendarSettingsPageViewModel));
|
||||||
services.AddTransient(typeof(CalendarAccountSettingsPageViewModel));
|
services.AddTransient(typeof(CalendarAccountSettingsPageViewModel));
|
||||||
services.AddTransient(typeof(EventDetailsPageViewModel));
|
services.AddTransient(typeof(EventDetailsPageViewModel));
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
x:Class="Wino.Mail.WinUI.Controls.AppModeFooterSwitcherControl"
|
x:Class="Wino.Mail.WinUI.Controls.AppModeFooterSwitcherControl"
|
||||||
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"
|
||||||
|
xmlns:animatedvisuals="using:Microsoft.UI.Xaml.Controls.AnimatedVisuals"
|
||||||
xmlns:controls="using:CommunityToolkit.WinUI.Controls"
|
xmlns:controls="using:CommunityToolkit.WinUI.Controls"
|
||||||
xmlns:domain="using:Wino.Core.Domain"
|
xmlns:domain="using:Wino.Core.Domain"
|
||||||
Loaded="ControlLoaded"
|
Loaded="ControlLoaded"
|
||||||
@@ -27,6 +28,11 @@
|
|||||||
<FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="" />
|
<FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="" />
|
||||||
</controls:SegmentedItem.Icon>
|
</controls:SegmentedItem.Icon>
|
||||||
</controls:SegmentedItem>
|
</controls:SegmentedItem>
|
||||||
|
<controls:SegmentedItem ToolTipService.ToolTip="{x:Bind domain:Translator.MenuSettings, Mode=OneWay}">
|
||||||
|
<controls:SegmentedItem.Icon>
|
||||||
|
<SymbolIcon Symbol="Setting" />
|
||||||
|
</controls:SegmentedItem.Icon>
|
||||||
|
</controls:SegmentedItem>
|
||||||
</controls:Segmented>
|
</controls:Segmented>
|
||||||
</Grid>
|
</Grid>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using Microsoft.UI.Xaml;
|
|||||||
using Microsoft.UI.Xaml.Controls;
|
using Microsoft.UI.Xaml.Controls;
|
||||||
using Wino.Core.Domain.Enums;
|
using Wino.Core.Domain.Enums;
|
||||||
using Wino.Core.Domain.Interfaces;
|
using Wino.Core.Domain.Interfaces;
|
||||||
|
using Wino.Core.Domain;
|
||||||
|
|
||||||
namespace Wino.Mail.WinUI.Controls;
|
namespace Wino.Mail.WinUI.Controls;
|
||||||
|
|
||||||
@@ -44,6 +45,13 @@ public sealed partial class AppModeFooterSwitcherControl : UserControl
|
|||||||
if (_isUpdatingSelection)
|
if (_isUpdatingSelection)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (ModeSegmentedControl.SelectedIndex == 3)
|
||||||
|
{
|
||||||
|
_navigationService.Navigate(WinoPage.SettingsPage);
|
||||||
|
UpdateSelection(_statePersistenceService.ApplicationMode);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var selectedMode = ModeSegmentedControl.SelectedIndex switch
|
var selectedMode = ModeSegmentedControl.SelectedIndex switch
|
||||||
{
|
{
|
||||||
1 => WinoApplicationMode.Calendar,
|
1 => WinoApplicationMode.Calendar,
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ public partial class CustomCalendarFlipView : FlipView
|
|||||||
HideButton(PreviousButtonVertical);
|
HideButton(PreviousButtonVertical);
|
||||||
HideButton(NextButtonVertical);
|
HideButton(NextButtonVertical);
|
||||||
|
|
||||||
|
SelectionChanged -= FlipViewSelectionChanged;
|
||||||
SelectionChanged += FlipViewSelectionChanged;
|
SelectionChanged += FlipViewSelectionChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ using Wino.Helpers;
|
|||||||
|
|
||||||
namespace Wino.Calendar.Controls;
|
namespace Wino.Calendar.Controls;
|
||||||
|
|
||||||
public partial class WinoCalendarControl : Control
|
public partial class WinoCalendarControl : Control, IDisposable
|
||||||
{
|
{
|
||||||
private const string PART_WinoFlipView = nameof(PART_WinoFlipView);
|
private const string PART_WinoFlipView = nameof(PART_WinoFlipView);
|
||||||
private const string PART_IdleGrid = nameof(PART_IdleGrid);
|
private const string PART_IdleGrid = nameof(PART_IdleGrid);
|
||||||
@@ -93,6 +93,12 @@ public partial class WinoCalendarControl : Control
|
|||||||
partial void OnIsFlipIdleChanged(bool newValue)
|
partial void OnIsFlipIdleChanged(bool newValue)
|
||||||
=> UpdateIdleState();
|
=> UpdateIdleState();
|
||||||
|
|
||||||
|
partial void OnDayRangesChanged(ObservableCollection<DayRangeRenderModel>? newValue)
|
||||||
|
=> EnsureStableSelection();
|
||||||
|
|
||||||
|
partial void OnSelectedFlipViewDayRangeChanged(DayRangeRenderModel? newValue)
|
||||||
|
=> EnsureStableSelection();
|
||||||
|
|
||||||
partial void OnActiveScrollViewerPropertyChanged(DependencyPropertyChangedEventArgs e)
|
partial void OnActiveScrollViewerPropertyChanged(DependencyPropertyChangedEventArgs e)
|
||||||
{
|
{
|
||||||
var newValue = e.NewValue as ScrollViewer;
|
var newValue = e.NewValue as ScrollViewer;
|
||||||
@@ -200,6 +206,23 @@ public partial class WinoCalendarControl : Control
|
|||||||
if (InternalFlipView != null)
|
if (InternalFlipView != null)
|
||||||
{
|
{
|
||||||
InternalFlipView.ProgrammaticNavigationCompleted -= InternalFlipViewProgrammaticNavigationCompleted;
|
InternalFlipView.ProgrammaticNavigationCompleted -= InternalFlipViewProgrammaticNavigationCompleted;
|
||||||
|
|
||||||
|
if (InternalFlipView is IDisposable disposableFlipView)
|
||||||
|
{
|
||||||
|
disposableFlipView.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_previousScrollViewer != null)
|
||||||
|
{
|
||||||
|
DeregisterScrollChanges(_previousScrollViewer);
|
||||||
|
_previousScrollViewer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_previousCanvas != null)
|
||||||
|
{
|
||||||
|
DeregisterCanvas(_previousCanvas);
|
||||||
|
_previousCanvas = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
InternalFlipView = GetTemplateChild(PART_WinoFlipView) as WinoCalendarFlipView;
|
InternalFlipView = GetTemplateChild(PART_WinoFlipView) as WinoCalendarFlipView;
|
||||||
@@ -213,6 +236,7 @@ public partial class WinoCalendarControl : Control
|
|||||||
UpdateIdleState();
|
UpdateIdleState();
|
||||||
ManageCalendarOrientation();
|
ManageCalendarOrientation();
|
||||||
ManageDisplayType();
|
ManageDisplayType();
|
||||||
|
EnsureStableSelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InternalFlipViewProgrammaticNavigationCompleted(object? sender, ProgrammaticNavigationCompletedEventArgs e)
|
private void InternalFlipViewProgrammaticNavigationCompleted(object? sender, ProgrammaticNavigationCompletedEventArgs e)
|
||||||
@@ -233,6 +257,33 @@ public partial class WinoCalendarControl : Control
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void EnsureStableSelection()
|
||||||
|
{
|
||||||
|
if (InternalFlipView == null || DayRanges == null || DayRanges.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var targetIndex = SelectedFlipViewIndex;
|
||||||
|
|
||||||
|
if (SelectedFlipViewDayRange != null)
|
||||||
|
{
|
||||||
|
var selectedRangeIndex = DayRanges.IndexOf(SelectedFlipViewDayRange);
|
||||||
|
if (selectedRangeIndex >= 0)
|
||||||
|
{
|
||||||
|
targetIndex = selectedRangeIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetIndex < 0 || targetIndex >= DayRanges.Count)
|
||||||
|
{
|
||||||
|
targetIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (InternalFlipView.SelectedIndex != targetIndex)
|
||||||
|
{
|
||||||
|
InternalFlipView.SelectedIndex = targetIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void ActiveTimelineCellUnselected(object? sender, TimelineCellUnselectedArgs e)
|
private void ActiveTimelineCellUnselected(object? sender, TimelineCellUnselectedArgs e)
|
||||||
=> TimelineCellUnselected?.Invoke(this, e);
|
=> TimelineCellUnselected?.Invoke(this, e);
|
||||||
|
|
||||||
@@ -291,4 +342,40 @@ public partial class WinoCalendarControl : Control
|
|||||||
{
|
{
|
||||||
return this.FindDescendants<CalendarItemControl>().FirstOrDefault(a => a.CalendarItem == calendarItemViewModel)!;
|
return this.FindDescendants<CalendarItemControl>().FirstOrDefault(a => a.CalendarItem == calendarItemViewModel)!;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
SizeChanged -= CalendarSizeChanged;
|
||||||
|
|
||||||
|
if (_previousScrollViewer != null)
|
||||||
|
{
|
||||||
|
DeregisterScrollChanges(_previousScrollViewer);
|
||||||
|
_previousScrollViewer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_previousCanvas != null)
|
||||||
|
{
|
||||||
|
DeregisterCanvas(_previousCanvas);
|
||||||
|
_previousCanvas = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (InternalFlipView != null)
|
||||||
|
{
|
||||||
|
InternalFlipView.ProgrammaticNavigationCompleted -= InternalFlipViewProgrammaticNavigationCompleted;
|
||||||
|
|
||||||
|
if (InternalFlipView is IDisposable disposableFlipView)
|
||||||
|
{
|
||||||
|
disposableFlipView.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
InternalFlipView = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
IdleGrid = null;
|
||||||
|
ActiveCanvas = null;
|
||||||
|
ActiveScrollViewer = null;
|
||||||
|
TimelineCellSelected = null;
|
||||||
|
TimelineCellUnselected = null;
|
||||||
|
ScrollPositionChanging = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ using Wino.Core.Domain.Models.Calendar;
|
|||||||
|
|
||||||
namespace Wino.Calendar.Controls;
|
namespace Wino.Calendar.Controls;
|
||||||
|
|
||||||
public partial class WinoCalendarFlipView : CustomCalendarFlipView
|
public partial class WinoCalendarFlipView : CustomCalendarFlipView, IDisposable
|
||||||
{
|
{
|
||||||
public static readonly DependencyProperty IsIdleProperty = DependencyProperty.Register(nameof(IsIdle), typeof(bool), typeof(WinoCalendarFlipView), new PropertyMetadata(true));
|
public static readonly DependencyProperty IsIdleProperty = DependencyProperty.Register(nameof(IsIdle), typeof(bool), typeof(WinoCalendarFlipView), new PropertyMetadata(true));
|
||||||
public static readonly DependencyProperty ActiveCanvasProperty = DependencyProperty.Register(nameof(ActiveCanvas), typeof(WinoDayTimelineCanvas), typeof(WinoCalendarFlipView), new PropertyMetadata(null));
|
public static readonly DependencyProperty ActiveCanvasProperty = DependencyProperty.Register(nameof(ActiveCanvas), typeof(WinoDayTimelineCanvas), typeof(WinoCalendarFlipView), new PropertyMetadata(null));
|
||||||
@@ -50,10 +50,11 @@ public partial class WinoCalendarFlipView : CustomCalendarFlipView
|
|||||||
internal event EventHandler<ProgrammaticNavigationCompletedEventArgs>? ProgrammaticNavigationCompleted;
|
internal event EventHandler<ProgrammaticNavigationCompletedEventArgs>? ProgrammaticNavigationCompleted;
|
||||||
|
|
||||||
private INotifyCollectionChanged? _trackedItemsSource;
|
private INotifyCollectionChanged? _trackedItemsSource;
|
||||||
|
private readonly long _itemsSourceCallbackToken;
|
||||||
|
|
||||||
public WinoCalendarFlipView()
|
public WinoCalendarFlipView()
|
||||||
{
|
{
|
||||||
RegisterPropertyChangedCallback(ItemsSourceProperty, new DependencyPropertyChangedCallback(OnItemsSourceChanged));
|
_itemsSourceCallbackToken = RegisterPropertyChangedCallback(ItemsSourceProperty, new DependencyPropertyChangedCallback(OnItemsSourceChanged));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void OnItemsSourceChanged(DependencyObject d, DependencyProperty e)
|
private static void OnItemsSourceChanged(DependencyObject d, DependencyProperty e)
|
||||||
@@ -207,6 +208,18 @@ public partial class WinoCalendarFlipView : CustomCalendarFlipView
|
|||||||
|
|
||||||
private ObservableRangeCollection<DayRangeRenderModel>? GetItemsSource()
|
private ObservableRangeCollection<DayRangeRenderModel>? GetItemsSource()
|
||||||
=> ItemsSource as ObservableRangeCollection<DayRangeRenderModel>;
|
=> ItemsSource as ObservableRangeCollection<DayRangeRenderModel>;
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (_trackedItemsSource != null)
|
||||||
|
{
|
||||||
|
_trackedItemsSource.CollectionChanged -= ItemsSourceUpdated;
|
||||||
|
_trackedItemsSource = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
UnregisterPropertyChangedCallback(ItemsSourceProperty, _itemsSourceCallbackToken);
|
||||||
|
ProgrammaticNavigationCompleted = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal sealed class ProgrammaticNavigationCompletedEventArgs : EventArgs
|
internal sealed class ProgrammaticNavigationCompletedEventArgs : EventArgs
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ using Wino.Helpers;
|
|||||||
|
|
||||||
namespace Wino.Calendar.Controls;
|
namespace Wino.Calendar.Controls;
|
||||||
|
|
||||||
public partial class WinoCalendarView : Control
|
public partial class WinoCalendarView : Control, IDisposable
|
||||||
{
|
{
|
||||||
private const string PART_DayViewItemBorder = nameof(PART_DayViewItemBorder);
|
private const string PART_DayViewItemBorder = nameof(PART_DayViewItemBorder);
|
||||||
private const string PART_CalendarView = nameof(PART_CalendarView);
|
private const string PART_CalendarView = nameof(PART_CalendarView);
|
||||||
@@ -54,6 +54,7 @@ public partial class WinoCalendarView : Control
|
|||||||
|
|
||||||
|
|
||||||
private CalendarView? CalendarView;
|
private CalendarView? CalendarView;
|
||||||
|
private long _displayModeCallbackToken = -1;
|
||||||
|
|
||||||
public WinoCalendarView()
|
public WinoCalendarView()
|
||||||
{
|
{
|
||||||
@@ -64,6 +65,17 @@ public partial class WinoCalendarView : Control
|
|||||||
{
|
{
|
||||||
base.OnApplyTemplate();
|
base.OnApplyTemplate();
|
||||||
|
|
||||||
|
if (CalendarView != null)
|
||||||
|
{
|
||||||
|
CalendarView.SelectedDatesChanged -= InternalCalendarViewSelectionChanged;
|
||||||
|
|
||||||
|
if (_displayModeCallbackToken != -1)
|
||||||
|
{
|
||||||
|
CalendarView.UnregisterPropertyChangedCallback(CalendarView.DisplayModeProperty, _displayModeCallbackToken);
|
||||||
|
_displayModeCallbackToken = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CalendarView = GetTemplateChild(PART_CalendarView) as CalendarView;
|
CalendarView = GetTemplateChild(PART_CalendarView) as CalendarView;
|
||||||
|
|
||||||
Guard.IsNotNull(CalendarView, nameof(CalendarView));
|
Guard.IsNotNull(CalendarView, nameof(CalendarView));
|
||||||
@@ -78,7 +90,7 @@ public partial class WinoCalendarView : Control
|
|||||||
// Everytime display mode changes, update the visible date range backgrounds.
|
// Everytime display mode changes, update the visible date range backgrounds.
|
||||||
// If users go back from year -> month -> day, we need to update the visible date range backgrounds.
|
// If users go back from year -> month -> day, we need to update the visible date range backgrounds.
|
||||||
|
|
||||||
CalendarView.RegisterPropertyChangedCallback(CalendarView.DisplayModeProperty, (s, e) => UpdateVisibleDateRangeBackgrounds());
|
_displayModeCallbackToken = CalendarView.RegisterPropertyChangedCallback(CalendarView.DisplayModeProperty, (s, e) => UpdateVisibleDateRangeBackgrounds());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InternalCalendarViewSelectionChanged(CalendarView sender, CalendarViewSelectedDatesChangedEventArgs args)
|
private void InternalCalendarViewSelectionChanged(CalendarView sender, CalendarViewSelectedDatesChangedEventArgs args)
|
||||||
@@ -147,4 +159,20 @@ public partial class WinoCalendarView : Control
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (CalendarView == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
CalendarView.SelectedDatesChanged -= InternalCalendarViewSelectionChanged;
|
||||||
|
|
||||||
|
if (_displayModeCallbackToken != -1)
|
||||||
|
{
|
||||||
|
CalendarView.UnregisterPropertyChangedCallback(CalendarView.DisplayModeProperty, _displayModeCallbackToken);
|
||||||
|
_displayModeCallbackToken = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
CalendarView = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"Wino.Mail.WinUI (Package)": {
|
"Wino.Mail.WinUI (Package)": {
|
||||||
"commandName": "MsixPackage",
|
"commandName": "MsixPackage",
|
||||||
"doNotLaunchApp": false,
|
"doNotLaunchApp": false,
|
||||||
"nativeDebugging": true
|
"nativeDebugging": false
|
||||||
},
|
},
|
||||||
"Wino.Mail.WinUI (Unpackaged)": {
|
"Wino.Mail.WinUI (Unpackaged)": {
|
||||||
"commandName": "Project"
|
"commandName": "Project"
|
||||||
|
|||||||
@@ -215,7 +215,10 @@ public class NavigationService : NavigationServiceBase, INavigationService
|
|||||||
|
|
||||||
if (coreFrame.Content is IShellHost shell)
|
if (coreFrame.Content is IShellHost shell)
|
||||||
{
|
{
|
||||||
shell.ActivateMode(mode, isInitialShellNavigation);
|
shell.ActivateMode(mode, new ShellModeActivationContext
|
||||||
|
{
|
||||||
|
IsInitialActivation = isInitialShellNavigation
|
||||||
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -93,7 +93,7 @@
|
|||||||
<Frame
|
<Frame
|
||||||
x:Name="MainShellFrame"
|
x:Name="MainShellFrame"
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
CacheSize="2"
|
CacheSize="0"
|
||||||
Navigated="MainFrameNavigated" />
|
Navigated="MainFrameNavigated" />
|
||||||
|
|
||||||
<coreControls:WinoInfoBar
|
<coreControls:WinoInfoBar
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:controls="using:Microsoft.UI.Xaml.Controls"
|
xmlns:controls="using:Microsoft.UI.Xaml.Controls"
|
||||||
xmlns:local="using:Wino.Mail.WinUI.Styles"
|
xmlns:local="using:Wino.Mail.WinUI.Styles"
|
||||||
xmlns:winoControls="using:Wino.Mail.WinUI.Controls"
|
xmlns:primitives="using:Microsoft.UI.Xaml.Controls.Primitives"
|
||||||
xmlns:primitives="using:Microsoft.UI.Xaml.Controls.Primitives">
|
xmlns:winoControls="using:Wino.Mail.WinUI.Controls">
|
||||||
|
|
||||||
<Style x:Key="CalendarShellNavigationViewStyle" TargetType="controls:NavigationView">
|
<Style x:Key="CalendarShellNavigationViewStyle" TargetType="controls:NavigationView">
|
||||||
<Setter Property="PaneToggleButtonStyle" Value="{StaticResource PaneToggleButtonStyle}" />
|
<Setter Property="PaneToggleButtonStyle" Value="{StaticResource PaneToggleButtonStyle}" />
|
||||||
|
|||||||
@@ -78,18 +78,6 @@ public sealed class WinoAppShellViewModel : CoreBaseViewModel, IShellViewModel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDispatcherAssigned()
|
|
||||||
{
|
|
||||||
base.OnDispatcherAssigned();
|
|
||||||
|
|
||||||
foreach (var client in _shellClients.Values)
|
|
||||||
{
|
|
||||||
client.Dispatcher = Dispatcher;
|
|
||||||
}
|
|
||||||
|
|
||||||
OnPropertyChanged(nameof(CurrentMenuItems));
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnNavigatedTo(Core.Domain.Models.Navigation.NavigationMode mode, object parameters)
|
public override void OnNavigatedTo(Core.Domain.Models.Navigation.NavigationMode mode, object parameters)
|
||||||
{
|
{
|
||||||
base.OnNavigatedTo(mode, parameters);
|
base.OnNavigatedTo(mode, parameters);
|
||||||
|
|||||||
@@ -7,6 +7,6 @@ public abstract class CalendarAppShellAbstract : BasePage<CalendarAppShellViewMo
|
|||||||
{
|
{
|
||||||
protected CalendarAppShellAbstract()
|
protected CalendarAppShellAbstract()
|
||||||
{
|
{
|
||||||
NavigationCacheMode = Microsoft.UI.Xaml.Navigation.NavigationCacheMode.Enabled;
|
NavigationCacheMode = Microsoft.UI.Xaml.Navigation.NavigationCacheMode.Disabled;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,6 @@ public abstract class CalendarPageAbstract : BasePage<CalendarPageViewModel>
|
|||||||
{
|
{
|
||||||
protected CalendarPageAbstract()
|
protected CalendarPageAbstract()
|
||||||
{
|
{
|
||||||
NavigationCacheMode = Microsoft.UI.Xaml.Navigation.NavigationCacheMode.Enabled;
|
NavigationCacheMode = Microsoft.UI.Xaml.Navigation.NavigationCacheMode.Disabled;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,6 @@ public abstract class ContactsAppShellAbstract : BasePage
|
|||||||
{
|
{
|
||||||
protected ContactsAppShellAbstract()
|
protected ContactsAppShellAbstract()
|
||||||
{
|
{
|
||||||
NavigationCacheMode = Microsoft.UI.Xaml.Navigation.NavigationCacheMode.Enabled;
|
NavigationCacheMode = Microsoft.UI.Xaml.Navigation.NavigationCacheMode.Disabled;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,13 @@
|
|||||||
|
using Microsoft.UI.Xaml.Navigation;
|
||||||
using Wino.Mail.WinUI;
|
using Wino.Mail.WinUI;
|
||||||
using Wino.Mail.ViewModels;
|
using Wino.Mail.ViewModels;
|
||||||
|
|
||||||
namespace Wino.Views.Abstract;
|
namespace Wino.Views.Abstract;
|
||||||
|
|
||||||
public abstract class ContactsPageAbstract : BasePage<ContactsPageViewModel> { }
|
public abstract class ContactsPageAbstract : BasePage<ContactsPageViewModel>
|
||||||
|
{
|
||||||
|
protected ContactsPageAbstract()
|
||||||
|
{
|
||||||
|
NavigationCacheMode = NavigationCacheMode.Disabled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,6 +7,6 @@ public abstract class MailAppShellAbstract : BasePage<MailAppShellViewModel>
|
|||||||
{
|
{
|
||||||
protected MailAppShellAbstract()
|
protected MailAppShellAbstract()
|
||||||
{
|
{
|
||||||
NavigationCacheMode = Microsoft.UI.Xaml.Navigation.NavigationCacheMode.Enabled;
|
NavigationCacheMode = Microsoft.UI.Xaml.Navigation.NavigationCacheMode.Disabled;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,13 @@
|
|||||||
|
using Microsoft.UI.Xaml.Navigation;
|
||||||
using Wino.Mail.WinUI;
|
using Wino.Mail.WinUI;
|
||||||
using Wino.Mail.ViewModels;
|
using Wino.Mail.ViewModels;
|
||||||
|
|
||||||
namespace Wino.Views.Abstract;
|
namespace Wino.Views.Abstract;
|
||||||
|
|
||||||
public partial class MailListPageAbstract : BasePage<MailListPageViewModel>;
|
public partial class MailListPageAbstract : BasePage<MailListPageViewModel>
|
||||||
|
{
|
||||||
|
protected MailListPageAbstract()
|
||||||
|
{
|
||||||
|
NavigationCacheMode = NavigationCacheMode.Disabled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,13 @@
|
|||||||
|
using Microsoft.UI.Xaml.Navigation;
|
||||||
using Wino.Mail.WinUI;
|
using Wino.Mail.WinUI;
|
||||||
using Wino.Core.ViewModels;
|
using Wino.Core.ViewModels;
|
||||||
|
|
||||||
namespace Wino.Views.Abstract;
|
namespace Wino.Views.Abstract;
|
||||||
|
|
||||||
public abstract class SettingsPageAbstract : BasePage<SettingsPageViewModel> { }
|
public abstract class SettingsPageAbstract : BasePage<SettingsPageViewModel>
|
||||||
|
{
|
||||||
|
protected SettingsPageAbstract()
|
||||||
|
{
|
||||||
|
NavigationCacheMode = NavigationCacheMode.Disabled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,6 +6,6 @@ public abstract class WinoAppShellAbstract : BasePage<WinoAppShellViewModel>
|
|||||||
{
|
{
|
||||||
protected WinoAppShellAbstract()
|
protected WinoAppShellAbstract()
|
||||||
{
|
{
|
||||||
NavigationCacheMode = Microsoft.UI.Xaml.Navigation.NavigationCacheMode.Enabled;
|
NavigationCacheMode = Microsoft.UI.Xaml.Navigation.NavigationCacheMode.Disabled;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:menu="using:Wino.Core.Domain.MenuItems"
|
xmlns:menu="using:Wino.Core.Domain.MenuItems"
|
||||||
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
|
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
|
||||||
|
Loaded="OnLoaded"
|
||||||
|
PreviewKeyDown="OnPreviewKeyDown"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
|
|
||||||
<Page.Resources>
|
<Page.Resources>
|
||||||
@@ -312,7 +314,7 @@
|
|||||||
<Frame
|
<Frame
|
||||||
x:Name="InnerShellFrame"
|
x:Name="InnerShellFrame"
|
||||||
Padding="0,0,7,7"
|
Padding="0,0,7,7"
|
||||||
CacheSize="2"
|
CacheSize="0"
|
||||||
IsNavigationStackEnabled="True">
|
IsNavigationStackEnabled="True">
|
||||||
<Frame.ContentTransitions>
|
<Frame.ContentTransitions>
|
||||||
<TransitionCollection>
|
<TransitionCollection>
|
||||||
|
|||||||
@@ -25,8 +25,6 @@ public sealed partial class CalendarAppShell : CalendarAppShellAbstract,
|
|||||||
public CalendarAppShell()
|
public CalendarAppShell()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
PreviewKeyDown += OnPreviewKeyDown;
|
|
||||||
Loaded += OnLoaded;
|
|
||||||
|
|
||||||
ManageCalendarDisplayType(ViewModel.StatePersistenceService.CalendarDisplayType);
|
ManageCalendarDisplayType(ViewModel.StatePersistenceService.CalendarDisplayType);
|
||||||
}
|
}
|
||||||
@@ -83,6 +81,14 @@ public sealed partial class CalendarAppShell : CalendarAppShellAbstract,
|
|||||||
{
|
{
|
||||||
base.OnNavigatedFrom(e);
|
base.OnNavigatedFrom(e);
|
||||||
|
|
||||||
|
InnerShellFrame.BackStack.Clear();
|
||||||
|
InnerShellFrame.ForwardStack.Clear();
|
||||||
|
|
||||||
|
if (InnerShellFrame.Content is IDisposable disposableContent)
|
||||||
|
{
|
||||||
|
disposableContent.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
Bindings.StopTracking();
|
Bindings.StopTracking();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,24 @@ public sealed partial class CalendarPage : CalendarPageAbstract,
|
|||||||
ViewModel.DetailsShowCalendarItemChanged += CalendarItemDetailContextChanged;
|
ViewModel.DetailsShowCalendarItemChanged += CalendarItemDetailContextChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
|
||||||
|
{
|
||||||
|
base.OnNavigatingFrom(e);
|
||||||
|
|
||||||
|
ViewModel.DetailsShowCalendarItemChanged -= CalendarItemDetailContextChanged;
|
||||||
|
QuickEventPopupDialog.IsOpen = false;
|
||||||
|
EventDetailsPopup.IsOpen = false;
|
||||||
|
EventDetailsPopup.PlacementTarget = null;
|
||||||
|
CalendarControl.ResetTimelineSelection();
|
||||||
|
|
||||||
|
if (CalendarControl is IDisposable disposableCalendarControl)
|
||||||
|
{
|
||||||
|
disposableCalendarControl.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
Bindings.StopTracking();
|
||||||
|
}
|
||||||
|
|
||||||
private void CalendarItemDetailContextChanged(object? sender, EventArgs e)
|
private void CalendarItemDetailContextChanged(object? sender, EventArgs e)
|
||||||
{
|
{
|
||||||
if (ViewModel.DisplayDetailsCalendarItemViewModel != null)
|
if (ViewModel.DisplayDetailsCalendarItemViewModel != null)
|
||||||
@@ -59,16 +77,29 @@ public sealed partial class CalendarPage : CalendarPageAbstract,
|
|||||||
WeakReferenceMessenger.Default.Unregister<GoPreviousDateRequestedMessage>(this);
|
WeakReferenceMessenger.Default.Unregister<GoPreviousDateRequestedMessage>(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Receive(ScrollToHourMessage message) => CalendarControl.NavigateToHour(message.TimeSpan);
|
public void Receive(ScrollToHourMessage message) => DispatcherQueue.TryEnqueue(() => CalendarControl.NavigateToHour(message.TimeSpan));
|
||||||
public void Receive(ScrollToDateMessage message) => CalendarControl.NavigateToDay(message.Date);
|
public void Receive(ScrollToDateMessage message) => DispatcherQueue.TryEnqueue(() => CalendarControl.NavigateToDay(message.Date));
|
||||||
public void Receive(GoNextDateRequestedMessage message) => CalendarControl.GoNextRange();
|
public void Receive(GoNextDateRequestedMessage message) => DispatcherQueue.TryEnqueue(() => CalendarControl.GoNextRange());
|
||||||
public void Receive(GoPreviousDateRequestedMessage message) => CalendarControl.GoPreviousRange();
|
public void Receive(GoPreviousDateRequestedMessage message) => DispatcherQueue.TryEnqueue(() => CalendarControl.GoPreviousRange());
|
||||||
|
|
||||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||||
{
|
{
|
||||||
base.OnNavigatedTo(e);
|
base.OnNavigatedTo(e);
|
||||||
|
|
||||||
if (e.NavigationMode == NavigationMode.Back) return;
|
if (e.NavigationMode == NavigationMode.Back)
|
||||||
|
{
|
||||||
|
if (ViewModel.RestoreVisibleState())
|
||||||
|
{
|
||||||
|
var restoreDate = ViewModel.GetRestoreDate();
|
||||||
|
DispatcherQueue.TryEnqueue(() => CalendarControl.NavigateToDay(restoreDate));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WeakReferenceMessenger.Default.Send(new LoadCalendarMessage(DateTime.Now.Date, CalendarInitInitiative.App));
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (e.Parameter is CalendarPageNavigationArgs args)
|
if (e.Parameter is CalendarPageNavigationArgs args)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -108,12 +108,11 @@
|
|||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
Command="{x:Bind ViewModel.NavigateExternalCommand}"
|
Command="{x:Bind ViewModel.NavigateExternalCommand}"
|
||||||
CommandParameter="Store"
|
CommandParameter="Store"
|
||||||
Style="{StaticResource AccentButtonStyle}"
|
|
||||||
ToolTipService.ToolTip="{x:Bind domain:Translator.SettingsStore_Title}">
|
ToolTipService.ToolTip="{x:Bind domain:Translator.SettingsStore_Title}">
|
||||||
<Viewbox Width="18" Height="18">
|
<Viewbox Width="18" Height="18">
|
||||||
<Path
|
<Path
|
||||||
Data="F1 M 19.003906 3.251953 L 19.003906 15.947266 C 19.003906 16.357422 18.920898 16.748047 18.754883 17.119141 C 18.588867 17.490234 18.367512 17.814127 18.09082 18.09082 C 17.814127 18.367514 17.490234 18.588867 17.119141 18.754883 C 16.748047 18.920898 16.357422 19.003906 15.947266 19.003906 L 3.056641 19.003906 C 2.646484 19.003906 2.255859 18.920898 1.884766 18.754883 C 1.513672 18.588867 1.189779 18.367514 0.913086 18.09082 C 0.636393 17.814127 0.415039 17.490234 0.249023 17.119141 C 0.083008 16.748047 0 16.357422 0 15.947266 L 0 3.251953 C 0 3.076172 0.032552 2.913412 0.097656 2.763672 C 0.16276 2.613934 0.252279 2.482098 0.366211 2.368164 C 0.480143 2.254232 0.611979 2.164715 0.761719 2.099609 C 0.911458 2.034506 1.074219 2.001953 1.25 2.001953 L 4.003906 2.001953 L 4.003906 0.996094 C 4.003906 0.859375 4.029948 0.730795 4.082031 0.610352 C 4.134114 0.48991 4.205729 0.384115 4.296875 0.292969 C 4.388021 0.201824 4.493815 0.130209 4.614258 0.078125 C 4.7347 0.026043 4.863281 0 5 0 L 14.003906 0 C 14.140624 0 14.269205 0.026043 14.389648 0.078125 C 14.510091 0.130209 14.615885 0.201824 14.707031 0.292969 C 14.798177 0.384115 14.869791 0.48991 14.921875 0.610352 C 14.973957 0.730795 14.999999 0.859375 15 0.996094 L 15 2.001953 L 17.753906 2.001953 C 17.923176 2.001953 18.084309 2.034506 18.237305 2.099609 C 18.390299 2.164715 18.523762 2.254232 18.637695 2.368164 C 18.751627 2.482098 18.841145 2.615561 18.90625 2.768555 C 18.971354 2.921551 19.003906 3.082684 19.003906 3.251953 Z M 14.003906 0.996094 L 5 0.996094 L 5 2.001953 L 14.003906 2.001953 Z M 5 10 L 9.003906 10 L 9.003906 5.996094 L 5 5.996094 Z M 10 10 L 14.003906 10 L 14.003906 5.996094 L 10 5.996094 Z M 5 15 L 9.003906 15 L 9.003906 10.996094 L 5 10.996094 Z M 10 15 L 14.003906 15 L 14.003906 10.996094 L 10 10.996094 Z "
|
Data="F1 M 19.003906 3.251953 L 19.003906 15.947266 C 19.003906 16.357422 18.920898 16.748047 18.754883 17.119141 C 18.588867 17.490234 18.367512 17.814127 18.09082 18.09082 C 17.814127 18.367514 17.490234 18.588867 17.119141 18.754883 C 16.748047 18.920898 16.357422 19.003906 15.947266 19.003906 L 3.056641 19.003906 C 2.646484 19.003906 2.255859 18.920898 1.884766 18.754883 C 1.513672 18.588867 1.189779 18.367514 0.913086 18.09082 C 0.636393 17.814127 0.415039 17.490234 0.249023 17.119141 C 0.083008 16.748047 0 16.357422 0 15.947266 L 0 3.251953 C 0 3.076172 0.032552 2.913412 0.097656 2.763672 C 0.16276 2.613934 0.252279 2.482098 0.366211 2.368164 C 0.480143 2.254232 0.611979 2.164715 0.761719 2.099609 C 0.911458 2.034506 1.074219 2.001953 1.25 2.001953 L 4.003906 2.001953 L 4.003906 0.996094 C 4.003906 0.859375 4.029948 0.730795 4.082031 0.610352 C 4.134114 0.48991 4.205729 0.384115 4.296875 0.292969 C 4.388021 0.201824 4.493815 0.130209 4.614258 0.078125 C 4.7347 0.026043 4.863281 0 5 0 L 14.003906 0 C 14.140624 0 14.269205 0.026043 14.389648 0.078125 C 14.510091 0.130209 14.615885 0.201824 14.707031 0.292969 C 14.798177 0.384115 14.869791 0.48991 14.921875 0.610352 C 14.973957 0.730795 14.999999 0.859375 15 0.996094 L 15 2.001953 L 17.753906 2.001953 C 17.923176 2.001953 18.084309 2.034506 18.237305 2.099609 C 18.390299 2.164715 18.523762 2.254232 18.637695 2.368164 C 18.751627 2.482098 18.841145 2.615561 18.90625 2.768555 C 18.971354 2.921551 19.003906 3.082684 19.003906 3.251953 Z M 14.003906 0.996094 L 5 0.996094 L 5 2.001953 L 14.003906 2.001953 Z M 5 10 L 9.003906 10 L 9.003906 5.996094 L 5 5.996094 Z M 10 10 L 14.003906 10 L 14.003906 5.996094 L 10 5.996094 Z M 5 15 L 9.003906 15 L 9.003906 10.996094 L 5 10.996094 Z M 10 15 L 14.003906 15 L 14.003906 10.996094 L 10 10.996094 Z "
|
||||||
Fill="{ThemeResource AccentTextFillColorPrimaryBrush}"
|
Fill="{ThemeResource TextFillColorPrimaryBrush}"
|
||||||
Stretch="Uniform" />
|
Stretch="Uniform" />
|
||||||
</Viewbox>
|
</Viewbox>
|
||||||
</Button>
|
</Button>
|
||||||
@@ -128,14 +127,14 @@
|
|||||||
Description="{x:Bind ViewModel.AccountSummaryText, Mode=OneWay}"
|
Description="{x:Bind ViewModel.AccountSummaryText, Mode=OneWay}"
|
||||||
Header="{x:Bind domain:Translator.SettingsManageAccountSettings_Title}"
|
Header="{x:Bind domain:Translator.SettingsManageAccountSettings_Title}"
|
||||||
IsClickEnabled="True"
|
IsClickEnabled="True"
|
||||||
Tag="{x:Bind enums:WinoPage.AccountManagementPage}">
|
Tag="{x:Bind enums:WinoPage.ManageAccountsPage}">
|
||||||
<controls:SettingsCard.HeaderIcon>
|
<controls:SettingsCard.HeaderIcon>
|
||||||
<FontIcon Foreground="{ThemeResource AccentTextFillColorPrimaryBrush}" Glyph="" />
|
<FontIcon Foreground="{ThemeResource AccentTextFillColorPrimaryBrush}" Glyph="" />
|
||||||
</controls:SettingsCard.HeaderIcon>
|
</controls:SettingsCard.HeaderIcon>
|
||||||
<Button
|
<Button
|
||||||
Click="SettingOptionClicked"
|
Click="SettingOptionClicked"
|
||||||
Style="{StaticResource AccentButtonStyle}"
|
Style="{StaticResource AccentButtonStyle}"
|
||||||
Tag="{x:Bind enums:WinoPage.AccountManagementPage}">
|
Tag="{x:Bind enums:WinoPage.ManageAccountsPage}">
|
||||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||||
<TextBlock Text="{x:Bind domain:Translator.Buttons_Manage}" />
|
<TextBlock Text="{x:Bind domain:Translator.Buttons_Manage}" />
|
||||||
<FontIcon FontSize="12" Glyph="" />
|
<FontIcon FontSize="12" Glyph="" />
|
||||||
|
|||||||
@@ -31,6 +31,9 @@ public sealed partial class SettingsPage : SettingsPageAbstract,
|
|||||||
// Register for frame navigation events to track back button visibility
|
// Register for frame navigation events to track back button visibility
|
||||||
SettingsFrame.Navigated -= SettingsFrameNavigated;
|
SettingsFrame.Navigated -= SettingsFrameNavigated;
|
||||||
SettingsFrame.Navigated += SettingsFrameNavigated;
|
SettingsFrame.Navigated += SettingsFrameNavigated;
|
||||||
|
PageHistory.Clear();
|
||||||
|
SettingsFrame.BackStack.Clear();
|
||||||
|
SettingsFrame.ForwardStack.Clear();
|
||||||
|
|
||||||
SettingsFrame.Navigate(typeof(SettingOptionsPage), null, new SuppressNavigationTransitionInfo());
|
SettingsFrame.Navigate(typeof(SettingOptionsPage), null, new SuppressNavigationTransitionInfo());
|
||||||
|
|
||||||
@@ -53,6 +56,10 @@ public sealed partial class SettingsPage : SettingsPageAbstract,
|
|||||||
case WinoPage.EmailTemplatesPage:
|
case WinoPage.EmailTemplatesPage:
|
||||||
WeakReferenceMessenger.Default.Send(new BreadcrumbNavigationRequested(Translator.SettingsEmailTemplates_Title, WinoPage.EmailTemplatesPage));
|
WeakReferenceMessenger.Default.Send(new BreadcrumbNavigationRequested(Translator.SettingsEmailTemplates_Title, WinoPage.EmailTemplatesPage));
|
||||||
break;
|
break;
|
||||||
|
case WinoPage.ManageAccountsPage:
|
||||||
|
case WinoPage.AccountManagementPage:
|
||||||
|
WeakReferenceMessenger.Default.Send(new BreadcrumbNavigationRequested(Translator.SettingsManageAccountSettings_Title, WinoPage.ManageAccountsPage));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -644,6 +644,7 @@
|
|||||||
<!-- Main Content -->
|
<!-- Main Content -->
|
||||||
<Frame
|
<Frame
|
||||||
x:Name="InnerShellFrame"
|
x:Name="InnerShellFrame"
|
||||||
|
CacheSize="0"
|
||||||
Padding="0,0,7,7"
|
Padding="0,0,7,7"
|
||||||
IsNavigationStackEnabled="True"
|
IsNavigationStackEnabled="True"
|
||||||
Navigated="ShellFrameContentNavigated">
|
Navigated="ShellFrameContentNavigated">
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ using Microsoft.UI.Xaml.Input;
|
|||||||
using Microsoft.UI.Xaml.Navigation;
|
using Microsoft.UI.Xaml.Navigation;
|
||||||
using Windows.Foundation;
|
using Windows.Foundation;
|
||||||
using Wino.Calendar.Controls;
|
using Wino.Calendar.Controls;
|
||||||
|
using Wino.Calendar.Views;
|
||||||
using Wino.Calendar.ViewModels;
|
using Wino.Calendar.ViewModels;
|
||||||
using Wino.Core.Domain;
|
using Wino.Core.Domain;
|
||||||
using Wino.Core.Domain.Entities.Mail;
|
using Wino.Core.Domain.Entities.Mail;
|
||||||
@@ -31,6 +32,9 @@ using Wino.Messaging.Client.Accounts;
|
|||||||
using Wino.Messaging.Client.Calendar;
|
using Wino.Messaging.Client.Calendar;
|
||||||
using Wino.Messaging.Client.Mails;
|
using Wino.Messaging.Client.Mails;
|
||||||
using Wino.Messaging.Client.Shell;
|
using Wino.Messaging.Client.Shell;
|
||||||
|
using Wino.Views.Mail;
|
||||||
|
using Wino.Views;
|
||||||
|
using Wino.Views.Settings;
|
||||||
|
|
||||||
namespace Wino.Mail.WinUI.Views;
|
namespace Wino.Mail.WinUI.Views;
|
||||||
|
|
||||||
@@ -51,6 +55,11 @@ public sealed partial class WinoAppShell : Views.Abstract.WinoAppShellAbstract,
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
|
var pageDispatcher = new WinUIDispatcher(DispatcherQueue);
|
||||||
|
ViewModel.MailClient.Dispatcher = pageDispatcher;
|
||||||
|
ViewModel.CalendarClient.Dispatcher = pageDispatcher;
|
||||||
|
ViewModel.GetClient(WinoApplicationMode.Contacts).Dispatcher = pageDispatcher;
|
||||||
|
|
||||||
ViewModel.MailClient.PropertyChanged += MailClientPropertyChanged;
|
ViewModel.MailClient.PropertyChanged += MailClientPropertyChanged;
|
||||||
ViewModel.CalendarClient.PropertyChanged += CalendarClientPropertyChanged;
|
ViewModel.CalendarClient.PropertyChanged += CalendarClientPropertyChanged;
|
||||||
ViewModel.StatePersistenceService.StatePropertyChanged += StatePersistenceServiceChanged;
|
ViewModel.StatePersistenceService.StatePropertyChanged += StatePersistenceServiceChanged;
|
||||||
@@ -66,30 +75,22 @@ public sealed partial class WinoAppShell : Views.Abstract.WinoAppShellAbstract,
|
|||||||
|
|
||||||
public Frame GetShellFrame() => InnerShellFrame;
|
public Frame GetShellFrame() => InnerShellFrame;
|
||||||
|
|
||||||
public void ActivateMode(WinoApplicationMode mode, bool isInitialActivation)
|
public void ActivateMode(WinoApplicationMode mode, ShellModeActivationContext activationContext)
|
||||||
{
|
{
|
||||||
if (_activeMode == mode && InnerShellFrame.Content != null)
|
if (_activeMode == mode && InnerShellFrame.Content != null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
DeactivateCurrentMode();
|
DeactivateCurrentMode();
|
||||||
|
ResetShellModeNavigationState();
|
||||||
|
|
||||||
_activeMode = mode;
|
_activeMode = mode;
|
||||||
ViewModel.SetCurrentMode(mode);
|
ViewModel.SetCurrentMode(mode);
|
||||||
|
|
||||||
RefreshNavigationViewBindings(syncMailSelection: mode != WinoApplicationMode.Mail);
|
RefreshNavigationViewBindings(syncMailSelection: mode != WinoApplicationMode.Mail);
|
||||||
|
|
||||||
//InnerShellFrame.IsNavigationStackEnabled = mode == WinoApplicationMode.Calendar;
|
|
||||||
//InnerShellFrame.BackStack.Clear();
|
|
||||||
//InnerShellFrame.ForwardStack.Clear();
|
|
||||||
|
|
||||||
ApplyModeLayout();
|
ApplyModeLayout();
|
||||||
UpdateTitleBarSubtitle();
|
UpdateTitleBarSubtitle();
|
||||||
|
|
||||||
var activationContext = new ShellModeActivationContext
|
|
||||||
{
|
|
||||||
IsInitialActivation = isInitialActivation
|
|
||||||
};
|
|
||||||
|
|
||||||
ViewModel.CurrentClient.Activate(activationContext);
|
ViewModel.CurrentClient.Activate(activationContext);
|
||||||
|
|
||||||
ApplyTitleBarContent();
|
ApplyTitleBarContent();
|
||||||
@@ -110,7 +111,10 @@ public sealed partial class WinoAppShell : Views.Abstract.WinoAppShellAbstract,
|
|||||||
|
|
||||||
if (_activeMode == null)
|
if (_activeMode == null)
|
||||||
{
|
{
|
||||||
ActivateMode(ViewModel.StatePersistenceService.ApplicationMode, true);
|
ActivateMode(ViewModel.StatePersistenceService.ApplicationMode, new ShellModeActivationContext
|
||||||
|
{
|
||||||
|
IsInitialActivation = true
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,16 +137,30 @@ public sealed partial class WinoAppShell : Views.Abstract.WinoAppShellAbstract,
|
|||||||
{
|
{
|
||||||
if (_activeMode == WinoApplicationMode.Mail)
|
if (_activeMode == WinoApplicationMode.Mail)
|
||||||
{
|
{
|
||||||
|
WeakReferenceMessenger.Default.Send(new ClearMailSelectionsRequested());
|
||||||
|
WeakReferenceMessenger.Default.Send(new DisposeRenderingFrameRequested());
|
||||||
|
ViewModel.StatePersistenceService.IsReadingMail = false;
|
||||||
ViewModel.MailClient.Deactivate();
|
ViewModel.MailClient.Deactivate();
|
||||||
}
|
}
|
||||||
else if (_activeMode == WinoApplicationMode.Calendar)
|
else if (_activeMode == WinoApplicationMode.Calendar)
|
||||||
{
|
{
|
||||||
|
ViewModel.StatePersistenceService.IsEventDetailsVisible = false;
|
||||||
ViewModel.CalendarClient.Deactivate();
|
ViewModel.CalendarClient.Deactivate();
|
||||||
}
|
}
|
||||||
else if (_activeMode == WinoApplicationMode.Contacts)
|
else if (_activeMode == WinoApplicationMode.Contacts)
|
||||||
{
|
{
|
||||||
ViewModel.CurrentClient.Deactivate();
|
ViewModel.CurrentClient.Deactivate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DynamicPageShellContentPresenter.Content = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ResetShellModeNavigationState()
|
||||||
|
{
|
||||||
|
ViewModel.StatePersistenceService.IsManageAccountsNavigating = false;
|
||||||
|
ViewModel.StatePersistenceService.IsSettingsNavigating = false;
|
||||||
|
InnerShellFrame.BackStack.Clear();
|
||||||
|
InnerShellFrame.ForwardStack.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ApplyTitleBarContent()
|
private void ApplyTitleBarContent()
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
namespace Wino.Messaging.Client.Navigation;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Navigates to manage accounts page.
|
|
||||||
/// </summary>
|
|
||||||
public record NavigateManageAccountsRequested;
|
|
||||||
Reference in New Issue
Block a user