Import functionality for wino accounts, calendar sync UI, bunch of shell improvements

This commit is contained in:
Burak Kaan Köse
2026-04-04 20:23:20 +02:00
parent 1667aa34db
commit 1d0fcfb5b0
68 changed files with 2792 additions and 519 deletions
@@ -23,7 +23,9 @@ public partial class AccountCalendarStateService : ObservableRecipient,
IRecipient<CalendarListAdded>,
IRecipient<CalendarListUpdated>,
IRecipient<CalendarListDeleted>,
IRecipient<AccountRemovedMessage>
IRecipient<AccountRemovedMessage>,
IRecipient<AccountUpdatedMessage>,
IRecipient<AccountCalendarSynchronizationStateChanged>
{
private readonly object _calendarStateLock = new();
@@ -41,6 +43,9 @@ public partial class AccountCalendarStateService : ObservableRecipient,
[ObservableProperty]
public partial ReadOnlyObservableGroupedCollection<MailAccount, AccountCalendarViewModel> GroupedCalendars { get; set; }
[ObservableProperty]
public partial bool IsAnySynchronizationInProgress { get; set; }
public IEnumerable<AccountCalendarViewModel> ActiveCalendars
{
get
@@ -84,6 +89,8 @@ public partial class AccountCalendarStateService : ObservableRecipient,
Messenger.Register<CalendarListUpdated>(this);
Messenger.Register<CalendarListDeleted>(this);
Messenger.Register<AccountRemovedMessage>(this);
Messenger.Register<AccountUpdatedMessage>(this);
Messenger.Register<AccountCalendarSynchronizationStateChanged>(this);
}
private void SingleGroupCalendarCollectiveStateChanged(object? sender, EventArgs e)
@@ -114,6 +121,8 @@ public partial class AccountCalendarStateService : ObservableRecipient,
group.Add(calendar);
}
}
UpdateAggregateSynchronizationState();
}
}
@@ -140,6 +149,8 @@ public partial class AccountCalendarStateService : ObservableRecipient,
_internalGroupedCalendars.Remove(group);
}
}
UpdateAggregateSynchronizationState();
}
}
@@ -340,4 +351,60 @@ public partial class AccountCalendarStateService : ObservableRecipient,
}
}
}
public async void Receive(AccountUpdatedMessage message)
{
if (Dispatcher != null)
{
await Dispatcher.ExecuteOnUIThread(() => UpdateGroupedAccount(message.Account));
}
else
{
UpdateGroupedAccount(message.Account);
}
}
public async void Receive(AccountCalendarSynchronizationStateChanged message)
{
if (Dispatcher != null)
{
await Dispatcher.ExecuteOnUIThread(() => UpdateCalendarSynchronizationState(message));
}
else
{
UpdateCalendarSynchronizationState(message);
}
}
private void UpdateGroupedAccount(MailAccount updatedAccount)
{
GroupedAccountCalendarViewModel? groupedAccount;
lock (_calendarStateLock)
{
groupedAccount = _internalGroupedAccountCalendars.FirstOrDefault(a => a.Account.Id == updatedAccount.Id);
}
groupedAccount?.UpdateAccount(updatedAccount);
}
private void UpdateCalendarSynchronizationState(AccountCalendarSynchronizationStateChanged message)
{
GroupedAccountCalendarViewModel? groupedAccount;
lock (_calendarStateLock)
{
groupedAccount = _internalGroupedAccountCalendars.FirstOrDefault(a => a.Account.Id == message.AccountId);
}
if (groupedAccount == null)
return;
groupedAccount.IsSynchronizationInProgress = message.IsSynchronizationInProgress;
groupedAccount.SynchronizationStatus = message.SynchronizationStatus;
UpdateAggregateSynchronizationState();
}
private void UpdateAggregateSynchronizationState()
{
IsAnySynchronizationInProgress = _internalGroupedAccountCalendars.Any(a => a.IsSynchronizationInProgress);
}
}
+21 -2
View File
@@ -28,14 +28,16 @@ namespace Wino.Services;
public class DialogService : DialogServiceBase, IMailDialogService
{
private readonly IWinoAccountProfileService _winoAccountProfileService;
private readonly IWinoAccountDataSyncService _winoAccountDataSyncService;
public DialogService(INewThemeService themeService,
IConfigurationService configurationService,
IApplicationResourceManager<ResourceDictionary> applicationResourceManager,
IUpdateManager updateManager,
IWinoAccountProfileService winoAccountProfileService) : base(themeService, configurationService, applicationResourceManager, updateManager)
IWinoAccountProfileService winoAccountProfileService,
IWinoAccountDataSyncService winoAccountDataSyncService) : base(themeService, configurationService, applicationResourceManager)
{
_winoAccountProfileService = winoAccountProfileService;
_winoAccountDataSyncService = winoAccountDataSyncService;
}
public async Task<ICreateAccountAliasDialog> ShowCreateAccountAliasDialogAsync()
@@ -279,4 +281,21 @@ public class DialogService : DialogServiceBase, IMailDialogService
return dialog.Result;
}
public async Task<WinoAccountSyncExportResult?> ShowWinoAccountExportDialogAsync()
{
var dialog = new WinoAccountSyncExportDialog(_winoAccountDataSyncService)
{
RequestedTheme = ThemeService.RootTheme.ToWindowsElementTheme()
};
await HandleDialogPresentationAsync(dialog);
if (dialog.FailureException != null)
{
throw dialog.FailureException;
}
return dialog.Result;
}
}
+1 -15
View File
@@ -16,7 +16,6 @@ using Wino.Core.Domain.Interfaces;
using Wino.Core.Domain.Models.Accounts;
using Wino.Core.Domain.Models.Common;
using Wino.Core.Domain.Models.Printing;
using Wino.Core.Domain.Models.Updates;
using Wino.Dialogs;
using Wino.Mail.WinUI.Dialogs;
using Wino.Mail.WinUI.Extensions;
@@ -31,16 +30,13 @@ public class DialogServiceBase : IDialogServiceBase
protected INewThemeService ThemeService { get; }
protected IConfigurationService ConfigurationService { get; }
protected IUpdateManager UpdateManager { get; }
protected IApplicationResourceManager<ResourceDictionary> ApplicationResourceManager { get; }
public DialogServiceBase(INewThemeService themeService, IConfigurationService configurationService, IApplicationResourceManager<ResourceDictionary> applicationResourceManager, IUpdateManager updateManager)
public DialogServiceBase(INewThemeService themeService, IConfigurationService configurationService, IApplicationResourceManager<ResourceDictionary> applicationResourceManager)
{
ThemeService = themeService;
ConfigurationService = configurationService;
ApplicationResourceManager = applicationResourceManager;
UpdateManager = updateManager;
}
protected XamlRoot? GetXamlRoot()
@@ -392,14 +388,4 @@ public class DialogServiceBase : IDialogServiceBase
return null!;
}
}
public async Task ShowWhatIsNewDialogAsync(UpdateNotes notes)
{
var dialog = new WhatIsNewDialog(notes, UpdateManager)
{
RequestedTheme = ThemeService.RootTheme.ToWindowsElementTheme()
};
await HandleDialogPresentationAsync(dialog);
}
}
+10 -3
View File
@@ -219,10 +219,13 @@ public class NavigationService : NavigationServiceBase, INavigationService
public bool ChangeApplicationMode(WinoApplicationMode mode)
=> ExecuteOnNavigationThread(() => ChangeApplicationModeInternal(mode));
public bool ChangeApplicationMode(WinoApplicationMode mode, ShellModeActivationContext activationContext)
=> ExecuteOnNavigationThread(() => ChangeApplicationModeInternal(mode, activationContext));
public bool CanGoBack()
=> ExecuteOnNavigationThread(CanGoBackInternal);
private bool ChangeApplicationModeInternal(WinoApplicationMode mode, object? activationParameter = null)
private bool ChangeApplicationModeInternal(WinoApplicationMode mode, ShellModeActivationContext? activationContext = null)
{
var coreFrame = GetCoreFrameInternal(NavigationReferenceFrame.ShellFrame);
@@ -254,7 +257,8 @@ public class NavigationService : NavigationServiceBase, INavigationService
shell.ActivateMode(mode, new ShellModeActivationContext
{
IsInitialActivation = isInitialShellNavigation,
Parameter = activationParameter
SuppressStartupFlows = activationContext?.SuppressStartupFlows ?? false,
Parameter = activationContext?.Parameter
});
ResetCurrentModeBackStackState();
@@ -280,7 +284,10 @@ public class NavigationService : NavigationServiceBase, INavigationService
{
if (_statePersistanceService.ApplicationMode != WinoApplicationMode.Settings)
{
return ChangeApplicationModeInternal(WinoApplicationMode.Settings, settingsTarget);
return ChangeApplicationModeInternal(WinoApplicationMode.Settings, new ShellModeActivationContext
{
Parameter = settingsTarget
});
}
page = WinoPage.SettingsPage;