Proper cleanup of account on the UI when its deleted.
This commit is contained in:
@@ -20,6 +20,7 @@ using Wino.Core.ViewModels;
|
||||
using Wino.Messaging.Client.Calendar;
|
||||
using Wino.Messaging.Client.Navigation;
|
||||
using Wino.Messaging.Server;
|
||||
using Wino.Messaging.UI;
|
||||
|
||||
namespace Wino.Calendar.ViewModels;
|
||||
|
||||
@@ -27,7 +28,8 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel,
|
||||
IRecipient<VisibleDateRangeChangedMessage>,
|
||||
IRecipient<CalendarEnableStatusChangedMessage>,
|
||||
IRecipient<NavigateManageAccountsRequested>,
|
||||
IRecipient<CalendarDisplayTypeChangedMessage>
|
||||
IRecipient<CalendarDisplayTypeChangedMessage>,
|
||||
IRecipient<AccountRemovedMessage>
|
||||
{
|
||||
public IPreferencesService PreferencesService { get; }
|
||||
public IStatePersistanceService StatePersistenceService { get; }
|
||||
@@ -110,7 +112,12 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel,
|
||||
{
|
||||
base.OnNavigatedTo(mode, parameters);
|
||||
|
||||
if (mode == NavigationMode.Back) return;
|
||||
// Account list may have changed while this shell was inactive.
|
||||
if (mode == NavigationMode.Back)
|
||||
{
|
||||
await InitializeAccountCalendarsAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateDateNavigationHeaderItems();
|
||||
|
||||
@@ -300,6 +307,7 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel,
|
||||
Messenger.Register<CalendarEnableStatusChangedMessage>(this);
|
||||
Messenger.Register<NavigateManageAccountsRequested>(this);
|
||||
Messenger.Register<CalendarDisplayTypeChangedMessage>(this);
|
||||
Messenger.Register<AccountRemovedMessage>(this);
|
||||
}
|
||||
|
||||
protected override void UnregisterRecipients()
|
||||
@@ -310,6 +318,7 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel,
|
||||
Messenger.Unregister<CalendarEnableStatusChangedMessage>(this);
|
||||
Messenger.Unregister<NavigateManageAccountsRequested>(this);
|
||||
Messenger.Unregister<CalendarDisplayTypeChangedMessage>(this);
|
||||
Messenger.Unregister<AccountRemovedMessage>(this);
|
||||
}
|
||||
|
||||
public void Receive(VisibleDateRangeChangedMessage message) => HighlightedDateRange = message.DateRange;
|
||||
@@ -403,4 +412,7 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel,
|
||||
OnPropertyChanged(nameof(IsVerticalCalendar));
|
||||
UpdateDateNavigationHeaderItems();
|
||||
}
|
||||
|
||||
public async void Receive(AccountRemovedMessage message)
|
||||
=> await InitializeAccountCalendarsAsync();
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ using Wino.Core.Domain.Models.Calendar.CalendarTypeStrategies;
|
||||
using Wino.Core.Domain.Models.Navigation;
|
||||
using Wino.Core.ViewModels;
|
||||
using Wino.Messaging.Client.Calendar;
|
||||
using Wino.Messaging.UI;
|
||||
|
||||
namespace Wino.Calendar.ViewModels;
|
||||
|
||||
@@ -31,7 +32,8 @@ public partial class CalendarPageViewModel : CalendarBaseViewModel,
|
||||
IRecipient<CalendarSettingsUpdatedMessage>,
|
||||
IRecipient<CalendarItemTappedMessage>,
|
||||
IRecipient<CalendarItemDoubleTappedMessage>,
|
||||
IRecipient<CalendarItemRightTappedMessage>
|
||||
IRecipient<CalendarItemRightTappedMessage>,
|
||||
IRecipient<AccountRemovedMessage>
|
||||
{
|
||||
#region Quick Event Creation
|
||||
|
||||
@@ -177,6 +179,7 @@ public partial class CalendarPageViewModel : CalendarBaseViewModel,
|
||||
Messenger.Register<CalendarItemTappedMessage>(this);
|
||||
Messenger.Register<CalendarItemDoubleTappedMessage>(this);
|
||||
Messenger.Register<CalendarItemRightTappedMessage>(this);
|
||||
Messenger.Register<AccountRemovedMessage>(this);
|
||||
}
|
||||
protected override void UnregisterRecipients()
|
||||
{
|
||||
@@ -187,6 +190,7 @@ public partial class CalendarPageViewModel : CalendarBaseViewModel,
|
||||
Messenger.Unregister<CalendarItemTappedMessage>(this);
|
||||
Messenger.Unregister<CalendarItemDoubleTappedMessage>(this);
|
||||
Messenger.Unregister<CalendarItemRightTappedMessage>(this);
|
||||
Messenger.Unregister<AccountRemovedMessage>(this);
|
||||
}
|
||||
|
||||
private void AccountCalendarStateCollectivelyChanged(object sender, GroupedAccountCalendarViewModel e)
|
||||
@@ -928,6 +932,29 @@ public partial class CalendarPageViewModel : CalendarBaseViewModel,
|
||||
|
||||
public void Receive(CalendarItemRightTappedMessage message) { }
|
||||
|
||||
public async void Receive(AccountRemovedMessage message)
|
||||
{
|
||||
var removedAccountId = message.Account.Id;
|
||||
|
||||
await ExecuteUIThread(() =>
|
||||
{
|
||||
foreach (var dayRange in DayRanges)
|
||||
{
|
||||
foreach (var calendarDay in dayRange.CalendarDays)
|
||||
{
|
||||
calendarDay.EventsCollection.RemoveCalendarItems(item => item.AssignedCalendar?.AccountId == removedAccountId);
|
||||
}
|
||||
}
|
||||
|
||||
if (DisplayDetailsCalendarItemViewModel?.AssignedCalendar?.AccountId == removedAccountId)
|
||||
{
|
||||
DisplayDetailsCalendarItemViewModel = null;
|
||||
}
|
||||
|
||||
SelectedQuickEventAccountCalendar = AccountCalendarStateService.ActiveCalendars.FirstOrDefault(a => a.IsPrimary);
|
||||
});
|
||||
}
|
||||
|
||||
protected override async void OnCalendarItemDeleted(CalendarItem calendarItem)
|
||||
{
|
||||
base.OnCalendarItemDeleted(calendarItem);
|
||||
|
||||
@@ -115,6 +115,18 @@ public class CalendarEventCollection
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveCalendarItems(Func<ICalendarItem, bool> predicate)
|
||||
{
|
||||
if (predicate == null) return;
|
||||
|
||||
var itemsToRemove = _allItems.Where(predicate).ToList();
|
||||
|
||||
foreach (var item in itemsToRemove)
|
||||
{
|
||||
RemoveCalendarItem(item);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddCalendarItemInternal(ObservableRangeCollection<ICalendarItem> collection, ICalendarItem calendarItem, bool create = true)
|
||||
{
|
||||
if (calendarItem is not ICalendarItemViewModel viewModel)
|
||||
|
||||
@@ -221,7 +221,13 @@ public partial class MailAppShellViewModel : MailBaseViewModel,
|
||||
{
|
||||
base.OnNavigatedTo(mode, parameters);
|
||||
|
||||
if (mode == NavigationMode.Back) return;
|
||||
if (mode == NavigationMode.Back)
|
||||
{
|
||||
// Account list may have changed while this shell was inactive.
|
||||
await RecreateMenuItemsAsync();
|
||||
await RestoreSelectedAccountAfterMenuRefreshAsync(false);
|
||||
return;
|
||||
}
|
||||
|
||||
await CreateFooterItemsAsync();
|
||||
|
||||
@@ -904,22 +910,50 @@ public partial class MailAppShellViewModel : MailBaseViewModel,
|
||||
await LoadAccountsAsync();
|
||||
}
|
||||
|
||||
private async Task RestoreSelectedAccountAfterMenuRefreshAsync(bool automaticallyNavigateFirstItem)
|
||||
{
|
||||
IAccountMenuItem validSelectedMenuItem = null;
|
||||
bool hasPreviousSelection = latestSelectedAccountMenuItem != null;
|
||||
|
||||
if (hasPreviousSelection)
|
||||
{
|
||||
var selectedEntityId = latestSelectedAccountMenuItem.EntityId.GetValueOrDefault();
|
||||
|
||||
if (selectedEntityId != Guid.Empty &&
|
||||
MenuItems.TryGetAccountMenuItem(selectedEntityId, out IAccountMenuItem foundSelectedMenuItem))
|
||||
{
|
||||
validSelectedMenuItem = foundSelectedMenuItem;
|
||||
}
|
||||
else
|
||||
{
|
||||
latestSelectedAccountMenuItem = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (validSelectedMenuItem == null)
|
||||
{
|
||||
validSelectedMenuItem = MenuItems.FirstOrDefault(a => a is IAccountMenuItem) as IAccountMenuItem;
|
||||
hasPreviousSelection = false;
|
||||
}
|
||||
|
||||
if (validSelectedMenuItem != null)
|
||||
{
|
||||
await ChangeLoadedAccountAsync(validSelectedMenuItem, hasPreviousSelection || automaticallyNavigateFirstItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
await ExecuteUIThread(() => SelectedMenuItem = null);
|
||||
NavigationService.Navigate(WinoPage.WelcomePage);
|
||||
}
|
||||
}
|
||||
|
||||
public async void Receive(RefreshUnreadCountsMessage message)
|
||||
=> await UpdateUnreadItemCountAsync();
|
||||
|
||||
public async void Receive(AccountsMenuRefreshRequested message)
|
||||
{
|
||||
await RecreateMenuItemsAsync();
|
||||
|
||||
// Try to restore latest selected account.
|
||||
if (latestSelectedAccountMenuItem != null)
|
||||
{
|
||||
await ChangeLoadedAccountAsync(latestSelectedAccountMenuItem, navigateInbox: true);
|
||||
}
|
||||
else if (MenuItems.FirstOrDefault(a => a is IAccountMenuItem) is IAccountMenuItem firstAccount)
|
||||
{
|
||||
await ChangeLoadedAccountAsync(firstAccount, message.AutomaticallyNavigateFirstItem);
|
||||
}
|
||||
await RestoreSelectedAccountAfterMenuRefreshAsync(message.AutomaticallyNavigateFirstItem);
|
||||
}
|
||||
|
||||
public async void Receive(AccountFolderConfigurationUpdated message)
|
||||
@@ -949,8 +983,7 @@ public partial class MailAppShellViewModel : MailBaseViewModel,
|
||||
{
|
||||
await CreateFooterItemsAsync();
|
||||
await RecreateMenuItemsAsync();
|
||||
|
||||
await ChangeLoadedAccountAsync(latestSelectedAccountMenuItem, navigateInbox: false);
|
||||
await RestoreSelectedAccountAfterMenuRefreshAsync(false);
|
||||
}
|
||||
|
||||
private void ReorderAccountMenuItems(Dictionary<Guid, int> newAccountOrder)
|
||||
@@ -1073,7 +1106,17 @@ public partial class MailAppShellViewModel : MailBaseViewModel,
|
||||
Messenger.Unregister<AccountFolderConfigurationUpdated>(this);
|
||||
}
|
||||
|
||||
public void Receive(AccountRemovedMessage message) => Messenger.Send(new AccountsMenuRefreshRequested(false));
|
||||
public async void Receive(AccountRemovedMessage message)
|
||||
{
|
||||
if (latestSelectedAccountMenuItem?.HoldingAccounts?.Any(a => a.Id == message.Account.Id) == true)
|
||||
{
|
||||
latestSelectedAccountMenuItem = null;
|
||||
await ExecuteUIThread(() => SelectedMenuItem = null);
|
||||
}
|
||||
|
||||
await RecreateMenuItemsAsync();
|
||||
await RestoreSelectedAccountAfterMenuRefreshAsync(false);
|
||||
}
|
||||
|
||||
public async void Receive(AccountCreatedMessage message)
|
||||
{
|
||||
|
||||
@@ -10,6 +10,7 @@ using Wino.Calendar.ViewModels.Interfaces;
|
||||
using Wino.Core.Domain.Entities.Shared;
|
||||
using Wino.Core.Domain.Interfaces;
|
||||
using Wino.Messaging.Client.Calendar;
|
||||
using Wino.Messaging.UI;
|
||||
|
||||
namespace Wino.Mail.WinUI.Services;
|
||||
|
||||
@@ -21,7 +22,8 @@ public partial class AccountCalendarStateService : ObservableRecipient,
|
||||
IAccountCalendarStateService,
|
||||
IRecipient<CalendarListAdded>,
|
||||
IRecipient<CalendarListUpdated>,
|
||||
IRecipient<CalendarListDeleted>
|
||||
IRecipient<CalendarListDeleted>,
|
||||
IRecipient<AccountRemovedMessage>
|
||||
{
|
||||
public IDispatcher? Dispatcher { get; set; }
|
||||
|
||||
@@ -71,6 +73,7 @@ public partial class AccountCalendarStateService : ObservableRecipient,
|
||||
Messenger.Register<CalendarListAdded>(this);
|
||||
Messenger.Register<CalendarListUpdated>(this);
|
||||
Messenger.Register<CalendarListDeleted>(this);
|
||||
Messenger.Register<AccountRemovedMessage>(this);
|
||||
}
|
||||
|
||||
private void SingleGroupCalendarCollectiveStateChanged(object? sender, EventArgs e)
|
||||
@@ -277,4 +280,31 @@ public partial class AccountCalendarStateService : ObservableRecipient,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async void Receive(AccountRemovedMessage message)
|
||||
{
|
||||
var removedAccountId = message.Account.Id;
|
||||
|
||||
if (Dispatcher != null)
|
||||
{
|
||||
await Dispatcher.ExecuteOnUIThread(() =>
|
||||
{
|
||||
var groupedAccount = _internalGroupedAccountCalendars.FirstOrDefault(a => a.Account.Id == removedAccountId);
|
||||
|
||||
if (groupedAccount != null)
|
||||
{
|
||||
RemoveGroupedAccountCalendar(groupedAccount);
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
var groupedAccount = _internalGroupedAccountCalendars.FirstOrDefault(a => a.Account.Id == removedAccountId);
|
||||
|
||||
if (groupedAccount != null)
|
||||
{
|
||||
RemoveGroupedAccountCalendar(groupedAccount);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ using Wino.Core.Domain.Entities.Shared;
|
||||
using Wino.Core.Domain.Enums;
|
||||
using Wino.Core.Domain.Interfaces;
|
||||
using Wino.Core.Domain.Models.Accounts;
|
||||
using Wino.Messaging.Client.Calendar;
|
||||
using Wino.Messaging.Client.Accounts;
|
||||
using Wino.Messaging.UI;
|
||||
|
||||
@@ -289,8 +290,40 @@ public class AccountService : BaseDatabaseService, IAccountService
|
||||
|
||||
public async Task DeleteAccountAsync(MailAccount account)
|
||||
{
|
||||
// Collect calendar entities before deletion so we can notify UI subscribers.
|
||||
var accountCalendars = await Connection.Table<AccountCalendar>()
|
||||
.Where(a => a.AccountId == account.Id)
|
||||
.ToListAsync()
|
||||
.ConfigureAwait(false);
|
||||
|
||||
var deletedCalendarItems = new List<CalendarItem>();
|
||||
foreach (var accountCalendar in accountCalendars)
|
||||
{
|
||||
var calendarItems = await Connection.Table<CalendarItem>()
|
||||
.Where(a => a.CalendarId == accountCalendar.Id)
|
||||
.ToListAsync()
|
||||
.ConfigureAwait(false);
|
||||
|
||||
deletedCalendarItems.AddRange(calendarItems);
|
||||
}
|
||||
|
||||
await DeleteAccountMailCacheAsync(account.Id, AccountCacheResetReason.AccountRemoval);
|
||||
|
||||
// Delete calendar metadata and related records for this account.
|
||||
foreach (var calendarItem in deletedCalendarItems)
|
||||
{
|
||||
await Connection.Table<CalendarEventAttendee>().DeleteAsync(a => a.CalendarItemId == calendarItem.Id).ConfigureAwait(false);
|
||||
await Connection.Table<Reminder>().DeleteAsync(a => a.CalendarItemId == calendarItem.Id).ConfigureAwait(false);
|
||||
await Connection.Table<CalendarAttachment>().DeleteAsync(a => a.CalendarItemId == calendarItem.Id).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
foreach (var accountCalendar in accountCalendars)
|
||||
{
|
||||
await Connection.Table<CalendarItem>().DeleteAsync(a => a.CalendarId == accountCalendar.Id).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
await Connection.Table<AccountCalendar>().DeleteAsync(a => a.AccountId == account.Id).ConfigureAwait(false);
|
||||
|
||||
await Connection.Table<MailItemFolder>().DeleteAsync(a => a.MailAccountId == account.Id);
|
||||
await Connection.Table<AccountSignature>().DeleteAsync(a => a.MailAccountId == account.Id);
|
||||
await Connection.Table<MailAccountAlias>().DeleteAsync(a => a.AccountId == account.Id);
|
||||
@@ -338,6 +371,16 @@ public class AccountService : BaseDatabaseService, IAccountService
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var calendarItem in deletedCalendarItems)
|
||||
{
|
||||
WeakReferenceMessenger.Default.Send(new CalendarItemDeleted(calendarItem));
|
||||
}
|
||||
|
||||
foreach (var accountCalendar in accountCalendars)
|
||||
{
|
||||
WeakReferenceMessenger.Default.Send(new CalendarListDeleted(accountCalendar));
|
||||
}
|
||||
|
||||
ReportUIChange(new AccountRemovedMessage(account));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user