Remove connection manager.

This commit is contained in:
Burak Kaan Köse
2025-10-03 21:55:23 +02:00
parent e42ebb49ae
commit accffe8ef6
26 changed files with 120 additions and 1091 deletions
+3 -11
View File
@@ -34,7 +34,6 @@ public partial class AppShellViewModel : CalendarBaseViewModel,
public IStatePersistanceService StatePersistenceService { get; }
public IAccountCalendarStateService AccountCalendarStateService { get; }
public INavigationService NavigationService { get; }
public IWinoServerConnectionManager ServerConnectionManager { get; }
[ObservableProperty]
private bool _isEventDetailsPageActive;
@@ -45,11 +44,7 @@ public partial class AppShellViewModel : CalendarBaseViewModel,
[ObservableProperty]
private bool isCalendarEnabled;
/// <summary>
/// Gets or sets the active connection status of the Wino server.
/// </summary>
[ObservableProperty]
private WinoServerConnectionStatus activeConnectionStatus;
/// <summary>
/// Gets or sets the display date of the calendar.
@@ -79,8 +74,7 @@ public partial class AppShellViewModel : CalendarBaseViewModel,
IAccountService accountService,
ICalendarService calendarService,
IAccountCalendarStateService accountCalendarStateService,
INavigationService navigationService,
IWinoServerConnectionManager serverConnectionManager)
INavigationService navigationService)
{
_accountService = accountService;
_calendarService = calendarService;
@@ -90,7 +84,6 @@ public partial class AppShellViewModel : CalendarBaseViewModel,
AccountCalendarStateService.CollectiveAccountGroupSelectionStateChanged += AccountCalendarStateCollectivelyChanged;
NavigationService = navigationService;
ServerConnectionManager = serverConnectionManager;
PreferencesService = preferencesService;
StatePersistenceService = statePersistanceService;
@@ -286,8 +279,7 @@ public partial class AppShellViewModel : CalendarBaseViewModel,
[RelayCommand]
public void ManageAccounts() => NavigationService.Navigate(WinoPage.AccountManagementPage);
[RelayCommand]
private Task ReconnectServerAsync() => ServerConnectionManager.ConnectAsync();
[RelayCommand]
private void DateClicked(CalendarViewDayClickedEventArgs clickedDateArgs)
+4 -17
View File
@@ -119,13 +119,10 @@ public sealed partial class App : WinoApplication, IRecipient<NewCalendarSynchro
if (appServiceTriggerDetails.CallerPackageFamilyName == Package.Current.Id.FamilyName)
{
// Connection established from the fulltrust process
// This is no longer needed with the empty connection manager implementation
connectionBackgroundTaskDeferral = args.TaskInstance.GetDeferral();
args.TaskInstance.Canceled += OnConnectionBackgroundTaskCanceled;
AppServiceConnectionManager.Connection = appServiceTriggerDetails.AppServiceConnection;
WeakReferenceMessenger.Default.Send(new WinoServerConnectionEstablished());
}
}
}
@@ -138,22 +135,12 @@ public sealed partial class App : WinoApplication, IRecipient<NewCalendarSynchro
connectionBackgroundTaskDeferral?.Complete();
connectionBackgroundTaskDeferral = null;
AppServiceConnectionManager.Connection = null;
}
public async void Receive(NewCalendarSynchronizationRequested message)
{
try
{
var synchronizationResultResponse = await AppServiceConnectionManager.GetResponseAsync<CalendarSynchronizationResult, NewCalendarSynchronizationRequested>(message);
synchronizationResultResponse.ThrowIfFailed();
}
catch (WinoServerException serverException)
{
var dialogService = Services.GetService<ICalendarDialogService>();
dialogService.InfoBarMessage(Translator.Info_SyncFailedTitle, serverException.Message, InfoBarMessageType.Error);
}
// Synchronization is no longer performed through the server connection manager
// This method is kept for compatibility but doesn't perform any actual work
await Task.CompletedTask;
}
}
-2
View File
@@ -57,13 +57,11 @@
Grid.ColumnSpan="2"
BackButtonClicked="AppBarBackButtonClicked"
Canvas.ZIndex="150"
ConnectionStatus="{x:Bind ViewModel.ActiveConnectionStatus, Mode=OneWay}"
CoreWindowText="Wino Calendar"
IsBackButtonVisible="{x:Bind ViewModel.StatePersistenceService.IsBackButtonVisible, Mode=OneWay}"
IsNavigationPaneOpen="{x:Bind MainSplitView.IsPaneOpen, Mode=TwoWay}"
NavigationViewDisplayMode="{x:Bind helpers:XamlHelpers.NavigationViewDisplayModeConverter(MainSplitView.DisplayMode), Mode=OneWay}"
OpenPaneLength="{x:Bind ViewModel.StatePersistenceService.OpenPaneLength, Mode=OneWay}"
ReconnectCommand="{x:Bind ViewModel.ReconnectServerCommand}"
ShrinkShellContentOnExpansion="False"
SystemReserved="180">
<coreControls:WinoAppTitleBar.ShellFrameContent>
@@ -1,11 +0,0 @@
namespace Wino.Core.Domain.Enums;
/// <summary>
/// What should happen to server app when the client is terminated.
/// </summary>
public enum ServerBackgroundMode
{
MinimizedTray, // Still runs, tray icon is visible.
Invisible, // Still runs, tray icon is invisible.
Terminate // Server is terminated as Wino terminates.
}
@@ -1,10 +0,0 @@
namespace Wino.Core.Domain.Enums;
public enum WinoServerConnectionStatus
{
None,
Connecting,
Connected,
Disconnected,
Failed
}
@@ -1,11 +0,0 @@
using System;
namespace Wino.Core.Domain.Exceptions;
/// <summary>
/// All server crash types. Wino Server ideally should not throw anything else than this Exception type.
/// </summary>
public class WinoServerException : Exception
{
public WinoServerException(string message) : base(message) { }
}
@@ -30,11 +30,6 @@ public interface IPreferencesService : INotifyPropertyChanged
/// </summary>
bool IsNavigationPaneOpened { get; set; }
/// <summary>
/// Setting: Gets or sets what should happen to server app when the client is terminated.
/// </summary>
ServerBackgroundMode ServerTerminationBehavior { get; set; }
/// <summary>
/// Setting: Preferred time format for mail or calendar header display.
/// </summary>
@@ -1,11 +1,56 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Wino.Core.Domain.Enums;
using Wino.Core.Domain.Models.Server;
namespace Wino.Core.Domain.Interfaces;
/// <summary>
/// Simple wrapper class to maintain compatibility with the original WinoServerResponse structure.
/// </summary>
/// <typeparam name="T">Type of the expected response.</typeparam>
public class WinoServerResponse<T>
{
public bool IsSuccess { get; set; }
public string Message { get; set; }
public T Data { get; set; }
public static WinoServerResponse<T> CreateSuccessResponse(T data)
{
return new WinoServerResponse<T>
{
IsSuccess = true,
Data = data
};
}
public static WinoServerResponse<T> CreateErrorResponse(string message)
{
return new WinoServerResponse<T>
{
IsSuccess = false,
Message = message
};
}
public void ThrowIfFailed()
{
if (!IsSuccess)
throw new InvalidOperationException(Message);
}
}
/// <summary>
/// Connection status enum to maintain compatibility.
/// </summary>
public enum WinoServerConnectionStatus
{
None,
Connecting,
Connected,
Disconnected,
Failed
}
public interface IWinoServerConnectionManager
{
/// <summary>
@@ -1,39 +0,0 @@
using Wino.Core.Domain.Exceptions;
namespace Wino.Core.Domain.Models.Server;
/// <summary>
/// Encapsulates responses from the Wino server.
/// Exceptions are stored separately in the Message and StackTrace properties due to serialization issues.
/// </summary>
/// <typeparam name="T">Type of the expected response.</typeparam>
public class WinoServerResponse<T>
{
public bool IsSuccess { get; set; }
public string Message { get; set; }
public T Data { get; set; }
public static WinoServerResponse<T> CreateSuccessResponse(T data)
{
return new WinoServerResponse<T>
{
IsSuccess = true,
Data = data
};
}
public static WinoServerResponse<T> CreateErrorResponse(string message)
{
return new WinoServerResponse<T>
{
IsSuccess = false,
Message = message
};
}
public void ThrowIfFailed()
{
if (!IsSuccess)
throw new WinoServerException(Message);
}
}
File diff suppressed because one or more lines are too long
@@ -1,255 +0,0 @@
using System.Windows.Input;
using Windows.Foundation;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Wino.Core.Domain.Enums;
namespace Wino.Core.WinUI.Controls;
public sealed partial class WinoAppTitleBar : UserControl
{
public event TypedEventHandler<WinoAppTitleBar, RoutedEventArgs> BackButtonClicked;
public static readonly DependencyProperty IsRenderingPaneVisibleProperty = DependencyProperty.Register(nameof(IsRenderingPaneVisible), typeof(bool), typeof(WinoAppTitleBar), new PropertyMetadata(false, OnDrawingPropertyChanged));
public static readonly DependencyProperty IsReaderNarrowedProperty = DependencyProperty.Register(nameof(IsReaderNarrowed), typeof(bool), typeof(WinoAppTitleBar), new PropertyMetadata(false, OnIsReaderNarrowedChanged));
public static readonly DependencyProperty IsBackButtonVisibleProperty = DependencyProperty.Register(nameof(IsBackButtonVisible), typeof(bool), typeof(WinoAppTitleBar), new PropertyMetadata(false, OnDrawingPropertyChanged));
public static readonly DependencyProperty OpenPaneLengthProperty = DependencyProperty.Register(nameof(OpenPaneLength), typeof(double), typeof(WinoAppTitleBar), new PropertyMetadata(0d, OnDrawingPropertyChanged));
public static readonly DependencyProperty IsNavigationPaneOpenProperty = DependencyProperty.Register(nameof(IsNavigationPaneOpen), typeof(bool), typeof(WinoAppTitleBar), new PropertyMetadata(false, OnDrawingPropertyChanged));
public static readonly DependencyProperty NavigationViewDisplayModeProperty = DependencyProperty.Register(nameof(NavigationViewDisplayMode), typeof(Microsoft.UI.Xaml.Controls.NavigationViewDisplayMode), typeof(WinoAppTitleBar), new PropertyMetadata(Microsoft.UI.Xaml.Controls.NavigationViewDisplayMode.Compact, OnDrawingPropertyChanged));
public static readonly DependencyProperty ShellFrameContentProperty = DependencyProperty.Register(nameof(ShellFrameContent), typeof(UIElement), typeof(WinoAppTitleBar), new PropertyMetadata(null, OnDrawingPropertyChanged));
public static readonly DependencyProperty SystemReservedProperty = DependencyProperty.Register(nameof(SystemReserved), typeof(double), typeof(WinoAppTitleBar), new PropertyMetadata(0, OnDrawingPropertyChanged));
public static readonly DependencyProperty CoreWindowTextProperty = DependencyProperty.Register(nameof(CoreWindowText), typeof(string), typeof(WinoAppTitleBar), new PropertyMetadata(string.Empty, OnDrawingPropertyChanged));
public static readonly DependencyProperty ReadingPaneLengthProperty = DependencyProperty.Register(nameof(ReadingPaneLength), typeof(double), typeof(WinoAppTitleBar), new PropertyMetadata(420d, OnDrawingPropertyChanged));
public static readonly DependencyProperty ConnectionStatusProperty = DependencyProperty.Register(nameof(ConnectionStatus), typeof(WinoServerConnectionStatus), typeof(WinoAppTitleBar), new PropertyMetadata(WinoServerConnectionStatus.None, new PropertyChangedCallback(OnConnectionStatusChanged)));
public static readonly DependencyProperty ReconnectCommandProperty = DependencyProperty.Register(nameof(ReconnectCommand), typeof(ICommand), typeof(WinoAppTitleBar), new PropertyMetadata(null));
public static readonly DependencyProperty ShrinkShellContentOnExpansionProperty = DependencyProperty.Register(nameof(ShrinkShellContentOnExpansion), typeof(bool), typeof(WinoAppTitleBar), new PropertyMetadata(true));
public static readonly DependencyProperty IsDragAreaProperty = DependencyProperty.Register(nameof(IsDragArea), typeof(bool), typeof(WinoAppTitleBar), new PropertyMetadata(false, new PropertyChangedCallback(OnIsDragAreaChanged)));
public static readonly DependencyProperty IsShellFrameContentVisibleProperty = DependencyProperty.Register(nameof(IsShellFrameContentVisible), typeof(bool), typeof(WinoAppTitleBar), new PropertyMetadata(true));
public static readonly DependencyProperty IsMenuButtonVisibleProperty = DependencyProperty.Register(nameof(IsMenuButtonVisible), typeof(bool), typeof(WinoAppTitleBar), new PropertyMetadata(true));
public bool IsShellFrameContentVisible
{
get { return (bool)GetValue(IsShellFrameContentVisibleProperty); }
set { SetValue(IsShellFrameContentVisibleProperty, value); }
}
public ICommand ReconnectCommand
{
get { return (ICommand)GetValue(ReconnectCommandProperty); }
set { SetValue(ReconnectCommandProperty, value); }
}
public WinoServerConnectionStatus ConnectionStatus
{
get { return (WinoServerConnectionStatus)GetValue(ConnectionStatusProperty); }
set { SetValue(ConnectionStatusProperty, value); }
}
public string CoreWindowText
{
get { return (string)GetValue(CoreWindowTextProperty); }
set { SetValue(CoreWindowTextProperty, value); }
}
public bool IsDragArea
{
get { return (bool)GetValue(IsDragAreaProperty); }
set { SetValue(IsDragAreaProperty, value); }
}
public double SystemReserved
{
get { return (double)GetValue(SystemReservedProperty); }
set { SetValue(SystemReservedProperty, value); }
}
public UIElement ShellFrameContent
{
get { return (UIElement)GetValue(ShellFrameContentProperty); }
set { SetValue(ShellFrameContentProperty, value); }
}
public Microsoft.UI.Xaml.Controls.NavigationViewDisplayMode NavigationViewDisplayMode
{
get { return (Microsoft.UI.Xaml.Controls.NavigationViewDisplayMode)GetValue(NavigationViewDisplayModeProperty); }
set { SetValue(NavigationViewDisplayModeProperty, value); }
}
public bool ShrinkShellContentOnExpansion
{
get { return (bool)GetValue(ShrinkShellContentOnExpansionProperty); }
set { SetValue(ShrinkShellContentOnExpansionProperty, value); }
}
public bool IsNavigationPaneOpen
{
get { return (bool)GetValue(IsNavigationPaneOpenProperty); }
set { SetValue(IsNavigationPaneOpenProperty, value); }
}
public double OpenPaneLength
{
get { return (double)GetValue(OpenPaneLengthProperty); }
set { SetValue(OpenPaneLengthProperty, value); }
}
public bool IsMenuButtonVisible
{
get { return (bool)GetValue(IsMenuButtonVisibleProperty); }
set { SetValue(IsMenuButtonVisibleProperty, value); }
}
public bool IsBackButtonVisible
{
get { return (bool)GetValue(IsBackButtonVisibleProperty); }
set { SetValue(IsBackButtonVisibleProperty, value); }
}
public bool IsReaderNarrowed
{
get { return (bool)GetValue(IsReaderNarrowedProperty); }
set { SetValue(IsReaderNarrowedProperty, value); }
}
public bool IsRenderingPaneVisible
{
get { return (bool)GetValue(IsRenderingPaneVisibleProperty); }
set { SetValue(IsRenderingPaneVisibleProperty, value); }
}
public double ReadingPaneLength
{
get { return (double)GetValue(ReadingPaneLengthProperty); }
set { SetValue(ReadingPaneLengthProperty, value); }
}
private static void OnIsReaderNarrowedChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
if (obj is WinoAppTitleBar bar)
{
bar.DrawTitleBar();
}
}
private static void OnDrawingPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
if (obj is WinoAppTitleBar bar)
{
bar.DrawTitleBar();
}
}
private static void OnConnectionStatusChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
if (obj is WinoAppTitleBar bar)
{
bar.UpdateConnectionStatus();
}
}
private static void OnIsDragAreaChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
if (obj is WinoAppTitleBar bar)
{
bar.SetDragArea();
}
}
private void SetDragArea()
{
if (IsDragArea)
{
Window.Current.SetTitleBar(dragbar);
}
}
private void UpdateConnectionStatus()
{
}
private void DrawTitleBar()
{
UpdateLayout();
CoreWindowTitleTextBlock.Visibility = Visibility.Collapsed;
ShellContentContainer.Width = double.NaN;
ShellContentContainer.Margin = new Thickness(0, 0, 0, 0);
ShellContentContainer.HorizontalAlignment = HorizontalAlignment.Stretch;
EmptySpaceWidth.Width = new GridLength(1, GridUnitType.Star);
// Menu is not visible.
if (NavigationViewDisplayMode == Microsoft.UI.Xaml.Controls.NavigationViewDisplayMode.Minimal)
{
}
else if (NavigationViewDisplayMode == Microsoft.UI.Xaml.Controls.NavigationViewDisplayMode.Compact)
{
// Icons are visible.
if (!IsReaderNarrowed && ShrinkShellContentOnExpansion)
{
ShellContentContainer.HorizontalAlignment = HorizontalAlignment.Left;
ShellContentContainer.Width = ReadingPaneLength;
}
}
else if (NavigationViewDisplayMode == Microsoft.UI.Xaml.Controls.NavigationViewDisplayMode.Expanded)
{
if (IsNavigationPaneOpen)
{
CoreWindowTitleTextBlock.Visibility = Visibility.Visible;
// LMargin = OpenPaneLength - LeftMenuStackPanel
ShellContentContainer.Margin = new Thickness(OpenPaneLength - LeftMenuStackPanel.ActualSize.X, 0, 0, 0);
if (!IsReaderNarrowed && ShrinkShellContentOnExpansion)
{
ShellContentContainer.HorizontalAlignment = HorizontalAlignment.Left;
ShellContentContainer.Width = ReadingPaneLength;
}
}
else
{
if (ShrinkShellContentOnExpansion)
{
EmptySpaceWidth.Width = new GridLength(ReadingPaneLength, GridUnitType.Pixel);
}
else
{
EmptySpaceWidth.Width = new GridLength(ReadingPaneLength, GridUnitType.Star);
}
}
}
}
public WinoAppTitleBar()
{
InitializeComponent();
}
private void BackClicked(object sender, RoutedEventArgs e)
{
BackButtonClicked?.Invoke(this, e);
}
private void PaneClicked(object sender, RoutedEventArgs e)
{
IsNavigationPaneOpen = !IsNavigationPaneOpen;
}
private void TitlebarSizeChanged(object sender, SizeChangedEventArgs e) => DrawTitleBar();
private void ReconnectClicked(object sender, RoutedEventArgs e)
{
// Close the popup for reconnect button.
ReconnectFlyout.Hide();
// Execute the reconnect command.
ReconnectCommand?.Execute(null);
}
}
+1 -1
View File
@@ -12,7 +12,7 @@ public static class CoreUWPContainerSetup
{
public static void RegisterCoreUWPServices(this IServiceCollection services)
{
var serverConnectionManager = new WinoServerConnectionManager();
var serverConnectionManager = new EmptyWinoServerConnectionManager<AppServiceConnection>();
services.AddSingleton<IWinoServerConnectionManager>(serverConnectionManager);
services.AddSingleton<IWinoServerConnectionManager<AppServiceConnection>>(serverConnectionManager);
+1 -1
View File
@@ -161,7 +161,7 @@ public static class XamlHelpers
return Translator.UnknownDateHeader;
}
public static bool ConnectionStatusEquals(WinoServerConnectionStatus winoServerConnectionStatus, WinoServerConnectionStatus connectionStatus) => winoServerConnectionStatus == connectionStatus;
#endregion
@@ -0,0 +1,55 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Wino.Core.Domain.Interfaces;
namespace Wino.Core.WinUI.Services;
/// <summary>
/// Empty implementation of IWinoServerConnectionManager that returns default values.
/// This replaces the old AppServiceConnection-based implementation.
/// </summary>
public class EmptyWinoServerConnectionManager : IWinoServerConnectionManager
{
public event EventHandler<WinoServerConnectionStatus> StatusChanged { add { } remove { } }
public WinoServerConnectionStatus Status => WinoServerConnectionStatus.Connected;
public TaskCompletionSource<bool> ConnectingHandle { get; } = new TaskCompletionSource<bool>();
public EmptyWinoServerConnectionManager()
{
ConnectingHandle.SetResult(true);
}
public Task<bool> ConnectAsync()
{
return Task.FromResult(true);
}
public Task QueueRequestAsync(IRequestBase request, Guid accountId)
{
return Task.CompletedTask;
}
public Task<WinoServerResponse<TResponse>> GetResponseAsync<TResponse, TRequestType>(TRequestType clientMessage, CancellationToken cancellationToken = default)
where TRequestType : IClientMessage
{
var response = WinoServerResponse<TResponse>.CreateSuccessResponse(default(TResponse));
return Task.FromResult(response);
}
}
/// <summary>
/// Generic empty implementation for typed connection managers.
/// </summary>
/// <typeparam name="TAppServiceConnection">The connection type (not used in this implementation)</typeparam>
public class EmptyWinoServerConnectionManager<TAppServiceConnection> : EmptyWinoServerConnectionManager, IWinoServerConnectionManager<TAppServiceConnection>
{
public TAppServiceConnection Connection { get; set; }
public Task InitializeAsync()
{
return Task.CompletedTask;
}
}
@@ -236,12 +236,6 @@ public class PreferencesService(IConfigurationService configurationService) : Ob
set => SaveProperty(propertyName: nameof(AutoSelectNextItem), value);
}
public ServerBackgroundMode ServerTerminationBehavior
{
get => _configurationService.Get(nameof(ServerTerminationBehavior), ServerBackgroundMode.MinimizedTray);
set => SaveProperty(propertyName: nameof(ServerTerminationBehavior), value);
}
public string DiagnosticId
{
get => _configurationService.Get(nameof(DiagnosticId), Guid.NewGuid().ToString());
@@ -1,369 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.Messaging;
using Nito.AsyncEx;
using Serilog;
using Windows.ApplicationModel;
using Windows.ApplicationModel.AppService;
using Windows.Foundation.Collections;
using Windows.Foundation.Metadata;
using Wino.Core.Domain.Enums;
using Wino.Core.Domain.Interfaces;
using Wino.Core.Domain.Models.Requests;
using Wino.Core.Domain.Models.Server;
using Wino.Core.Integration.Json;
using Wino.Messaging;
using Wino.Messaging.Client.Connection;
using Wino.Messaging.Enums;
using Wino.Messaging.Server;
using Wino.Messaging.UI;
namespace Wino.Core.WinUI.Services;
public class WinoServerConnectionManager :
IWinoServerConnectionManager<AppServiceConnection>,
IRecipient<WinoServerConnectionEstablished>
{
private const int ServerConnectionTimeoutMs = 10000;
public event EventHandler<WinoServerConnectionStatus> StatusChanged;
public TaskCompletionSource<bool> ConnectingHandle { get; private set; }
private ILogger Logger => Logger.ForContext<WinoServerConnectionManager>();
private WinoServerConnectionStatus status;
public WinoServerConnectionStatus Status
{
get { return status; }
private set
{
Log.Information("Server connection status changed to {Status}.", value);
status = value;
StatusChanged?.Invoke(this, value);
}
}
private AppServiceConnection _connection;
public AppServiceConnection Connection
{
get { return _connection; }
set
{
if (_connection != null)
{
_connection.RequestReceived -= ServerMessageReceived;
_connection.ServiceClosed -= ServerDisconnected;
}
_connection = value;
if (value == null)
{
Status = WinoServerConnectionStatus.Disconnected;
}
else
{
value.RequestReceived += ServerMessageReceived;
value.ServiceClosed += ServerDisconnected;
Status = WinoServerConnectionStatus.Connected;
}
}
}
private readonly JsonSerializerOptions _jsonSerializerOptions = new()
{
TypeInfoResolver = new ServerRequestTypeInfoResolver()
};
public WinoServerConnectionManager()
{
WeakReferenceMessenger.Default.Register(this);
}
public async Task<bool> ConnectAsync()
{
if (Status == WinoServerConnectionStatus.Connected)
{
Log.Information("Server is already connected.");
return true;
}
if (Status == WinoServerConnectionStatus.Connecting)
{
// A connection is already being established at the moment.
// No need to run another connection establishment process.
// Await the connecting handler if possible.
if (ConnectingHandle != null)
{
return await ConnectingHandle.Task;
}
}
if (ApiInformation.IsApiContractPresent("Windows.ApplicationModel.FullTrustAppContract", 1, 0))
{
try
{
ConnectingHandle = new TaskCompletionSource<bool>();
Status = WinoServerConnectionStatus.Connecting;
var connectionCancellationToken = new CancellationTokenSource(TimeSpan.FromMilliseconds(ServerConnectionTimeoutMs));
await FullTrustProcessLauncher.LaunchFullTrustProcessForCurrentAppAsync("WinoServer");
// Connection establishment handler is in App.xaml.cs OnBackgroundActivated.
// Once the connection is established, the handler will set the Connection property
// and WinoServerConnectionEstablished will be fired by the messenger.
await ConnectingHandle.Task.WaitAsync(connectionCancellationToken.Token);
Log.Information("Server connection established successfully.");
}
catch (OperationCanceledException canceledException)
{
Log.Error(canceledException, $"Server process did not start in {ServerConnectionTimeoutMs} ms. Operation is canceled.");
ConnectingHandle?.TrySetException(canceledException);
Status = WinoServerConnectionStatus.Failed;
return false;
}
catch (Exception ex)
{
Log.Error(ex, "Failed to connect to the server.");
ConnectingHandle?.TrySetException(ex);
Status = WinoServerConnectionStatus.Failed;
return false;
}
return true;
}
else
{
Log.Information("FullTrustAppContract is not present in the system. Server connection is not possible.");
}
return false;
}
public async Task InitializeAsync()
{
var isConnectionSuccessfull = await ConnectAsync();
if (isConnectionSuccessfull)
{
Log.Information("ServerConnectionManager initialized successfully.");
}
else
{
Log.Error("ServerConnectionManager initialization failed.");
}
}
private void ServerMessageReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args)
{
if (args.Request.Message.TryGetValue(MessageConstants.MessageTypeKey, out object messageTypeObject) && messageTypeObject is int messageTypeInt)
{
var messageType = (MessageType)messageTypeInt;
if (args.Request.Message.TryGetValue(MessageConstants.MessageDataKey, out object messageDataObject) && messageDataObject is string messageJson)
{
switch (messageType)
{
case MessageType.UIMessage:
if (!args.Request.Message.TryGetValue(MessageConstants.MessageDataTypeKey, out object dataTypeObject) || dataTypeObject is not string dataTypeName)
throw new ArgumentException("Message data type is missing.");
HandleUIMessage(messageJson, dataTypeName);
break;
default:
break;
}
}
}
}
/// <summary>
/// Unpacks IServerMessage objects and delegate it to Messenger for UI to process.
/// </summary>
/// <param name="messageJson">Message data in json format.</param>
private void HandleUIMessage(string messageJson, string typeName)
{
switch (typeName)
{
case nameof(MailAddedMessage):
WeakReferenceMessenger.Default.Send(JsonSerializer.Deserialize(messageJson, CommunicationMessagesContext.Default.MailAddedMessage));
break;
case nameof(MailDownloadedMessage):
WeakReferenceMessenger.Default.Send(JsonSerializer.Deserialize(messageJson, CommunicationMessagesContext.Default.MailDownloadedMessage));
break;
case nameof(MailRemovedMessage):
WeakReferenceMessenger.Default.Send(JsonSerializer.Deserialize(messageJson, CommunicationMessagesContext.Default.MailRemovedMessage));
break;
case nameof(MailUpdatedMessage):
WeakReferenceMessenger.Default.Send(JsonSerializer.Deserialize(messageJson, CommunicationMessagesContext.Default.MailUpdatedMessage));
break;
case nameof(AccountCreatedMessage):
WeakReferenceMessenger.Default.Send(JsonSerializer.Deserialize(messageJson, CommunicationMessagesContext.Default.AccountCreatedMessage));
break;
case nameof(AccountRemovedMessage):
WeakReferenceMessenger.Default.Send(JsonSerializer.Deserialize(messageJson, CommunicationMessagesContext.Default.AccountRemovedMessage));
break;
case nameof(AccountUpdatedMessage):
WeakReferenceMessenger.Default.Send(JsonSerializer.Deserialize(messageJson, CommunicationMessagesContext.Default.AccountUpdatedMessage));
break;
case nameof(DraftCreated):
WeakReferenceMessenger.Default.Send(JsonSerializer.Deserialize(messageJson, CommunicationMessagesContext.Default.DraftCreated));
break;
case nameof(DraftFailed):
WeakReferenceMessenger.Default.Send(JsonSerializer.Deserialize(messageJson, CommunicationMessagesContext.Default.DraftFailed));
break;
case nameof(DraftMapped):
WeakReferenceMessenger.Default.Send(JsonSerializer.Deserialize(messageJson, CommunicationMessagesContext.Default.DraftMapped));
break;
case nameof(FolderRenamed):
WeakReferenceMessenger.Default.Send(JsonSerializer.Deserialize(messageJson, CommunicationMessagesContext.Default.FolderRenamed));
break;
case nameof(FolderSynchronizationEnabled):
WeakReferenceMessenger.Default.Send(JsonSerializer.Deserialize(messageJson, CommunicationMessagesContext.Default.FolderSynchronizationEnabled));
break;
case nameof(MergedInboxRenamed):
WeakReferenceMessenger.Default.Send(JsonSerializer.Deserialize(messageJson, CommunicationMessagesContext.Default.MergedInboxRenamed));
break;
case nameof(AccountSynchronizationCompleted):
WeakReferenceMessenger.Default.Send(JsonSerializer.Deserialize(messageJson, CommunicationMessagesContext.Default.AccountSynchronizationCompleted));
break;
case nameof(RefreshUnreadCountsMessage):
WeakReferenceMessenger.Default.Send(JsonSerializer.Deserialize(messageJson, CommunicationMessagesContext.Default.RefreshUnreadCountsMessage));
break;
case nameof(AccountSynchronizerStateChanged):
WeakReferenceMessenger.Default.Send(JsonSerializer.Deserialize(messageJson, CommunicationMessagesContext.Default.AccountSynchronizerStateChanged));
break;
case nameof(AccountSynchronizationProgressUpdatedMessage):
WeakReferenceMessenger.Default.Send(JsonSerializer.Deserialize(messageJson, CommunicationMessagesContext.Default.AccountSynchronizationProgressUpdatedMessage));
break;
case nameof(AccountFolderConfigurationUpdated):
WeakReferenceMessenger.Default.Send(JsonSerializer.Deserialize(messageJson, CommunicationMessagesContext.Default.AccountFolderConfigurationUpdated));
break;
case nameof(CopyAuthURLRequested):
WeakReferenceMessenger.Default.Send(JsonSerializer.Deserialize(messageJson, CommunicationMessagesContext.Default.CopyAuthURLRequested));
break;
case nameof(NewMailSynchronizationRequested):
WeakReferenceMessenger.Default.Send(JsonSerializer.Deserialize(messageJson, CommunicationMessagesContext.Default.NewMailSynchronizationRequested));
break;
case nameof(AccountCacheResetMessage):
WeakReferenceMessenger.Default.Send(JsonSerializer.Deserialize(messageJson, CommunicationMessagesContext.Default.AccountCacheResetMessage));
break;
default:
throw new Exception("Invalid data type name passed to client.");
}
}
private void ServerDisconnected(AppServiceConnection sender, AppServiceClosedEventArgs args)
{
Log.Information("Server disconnected.");
}
public async Task QueueRequestAsync(IRequestBase request, Guid accountId)
{
var queuePackage = new ServerRequestPackage(accountId, request);
var queueResponse = await GetResponseInternalAsync<bool, ServerRequestPackage>(queuePackage, new Dictionary<string, object>()
{
{ MessageConstants.MessageDataRequestAccountIdKey, accountId }
});
queueResponse.ThrowIfFailed();
}
public Task<WinoServerResponse<TResponse>> GetResponseAsync<TResponse, TRequestType>(TRequestType message, CancellationToken cancellationToken = default) where TRequestType : IClientMessage
=> GetResponseInternalAsync<TResponse, TRequestType>(message, cancellationToken: cancellationToken);
[RequiresDynamicCode("Calls System.Text.Json.JsonSerializer.Serialize<TValue>(TValue, JsonSerializerOptions)")]
[RequiresUnreferencedCode("Calls System.Text.Json.JsonSerializer.Serialize<TValue>(TValue, JsonSerializerOptions)")]
private async Task<WinoServerResponse<TResponse>> GetResponseInternalAsync<TResponse, TRequestType>(TRequestType message,
Dictionary<string, object> parameters = null,
CancellationToken cancellationToken = default)
{
if (Status != WinoServerConnectionStatus.Connected)
await ConnectAsync();
if (Connection == null) return WinoServerResponse<TResponse>.CreateErrorResponse("Server connection is not established.");
string serializedMessage = string.Empty;
try
{
serializedMessage = JsonSerializer.Serialize(message, _jsonSerializerOptions);
}
catch (Exception serializationException)
{
Logger.Error(serializationException, $"Failed to serialize client message for sending.");
return WinoServerResponse<TResponse>.CreateErrorResponse($"Failed to serialize message.\n{serializationException.Message}");
}
AppServiceResponse response = null;
try
{
var valueSet = new ValueSet
{
{ MessageConstants.MessageTypeKey, (int)MessageType.ServerMessage },
{ MessageConstants.MessageDataKey, serializedMessage },
{ MessageConstants.MessageDataTypeKey, message.GetType().Name }
};
// Add additional parameters into ValueSet
if (parameters != null)
{
foreach (var item in parameters)
{
valueSet.Add(item.Key, item.Value);
}
}
response = await Connection.SendMessageAsync(valueSet).AsTask(cancellationToken);
}
catch (OperationCanceledException)
{
return WinoServerResponse<TResponse>.CreateErrorResponse($"Request is canceled by client.");
}
catch (Exception serverSendException)
{
Logger.Error(serverSendException, $"Failed to send message to server.");
return WinoServerResponse<TResponse>.CreateErrorResponse($"Failed to send message to server.\n{serverSendException.Message}");
}
// It should be always Success.
if (response.Status != AppServiceResponseStatus.Success)
return WinoServerResponse<TResponse>.CreateErrorResponse($"Wino Server responded with '{response.Status}' status to message delivery.");
// All responses must contain a message data.
if (!(response.Message.TryGetValue(MessageConstants.MessageDataKey, out object messageDataObject) && messageDataObject is string messageJson))
return WinoServerResponse<TResponse>.CreateErrorResponse("Server response did not contain message data.");
// Try deserialize the message data.
try
{
return JsonSerializer.Deserialize<WinoServerResponse<TResponse>>(messageJson);
}
catch (Exception jsonDeserializationError)
{
Logger.Error(jsonDeserializationError, $"Failed to deserialize server response message data.");
return WinoServerResponse<TResponse>.CreateErrorResponse($"Failed to deserialize Wino server response message data.\n{jsonDeserializationError.Message}");
}
}
public void Receive(WinoServerConnectionEstablished message)
=> ConnectingHandle?.TrySetResult(true);
}
-2
View File
@@ -32,7 +32,6 @@ public abstract class WinoApplication : Application, IRecipient<LanguageChanged>
public IServiceProvider Services { get; }
protected IWinoLogger LogInitializer { get; }
protected IApplicationConfiguration AppConfiguration { get; }
protected IWinoServerConnectionManager<AppServiceConnection> AppServiceConnectionManager { get; }
public INewThemeService NewThemeService { get; }
public IUnderlyingThemeService UnderlyingThemeService { get; }
public IThumbnailService ThumbnailService { get; }
@@ -54,7 +53,6 @@ public abstract class WinoApplication : Application, IRecipient<LanguageChanged>
LogInitializer = Services.GetService<IWinoLogger>();
AppConfiguration = Services.GetService<IApplicationConfiguration>();
AppServiceConnectionManager = Services.GetService<IWinoServerConnectionManager<AppServiceConnection>>();
NewThemeService = Services.GetService<INewThemeService>();
DatabaseService = Services.GetService<IDatabaseService>();
TranslationService = Services.GetService<ITranslationService>();
+2 -9
View File
@@ -138,15 +138,8 @@ public class WinoRequestDelegator : IWinoRequestDelegator
private async Task QueueRequestAsync(IRequestBase request, Guid accountId)
{
try
{
await EnsureServerConnectedAsync();
await _winoServerConnectionManager.QueueRequestAsync(request, accountId);
}
catch (WinoServerException serverException)
{
_dialogService.InfoBarMessage("Wino Server Exception", serverException.Message, InfoBarMessageType.Error);
}
await EnsureServerConnectedAsync();
await _winoServerConnectionManager.QueueRequestAsync(request, accountId);
}
private async Task QueueSynchronizationAsync(Guid accountId)
@@ -1,5 +1,4 @@
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
@@ -7,7 +6,6 @@ using Wino.Core.Domain;
using Wino.Core.Domain.Enums;
using Wino.Core.Domain.Interfaces;
using Wino.Core.Domain.Models.Navigation;
using Wino.Messaging.Server;
namespace Wino.Mail.ViewModels;
@@ -15,9 +13,6 @@ public partial class AppPreferencesPageViewModel : MailBaseViewModel
{
public IPreferencesService PreferencesService { get; }
[ObservableProperty]
private List<string> _appTerminationBehavior;
[ObservableProperty]
public partial List<string> SearchModes { get; set; }
@@ -41,18 +36,6 @@ public partial class AppPreferencesPageViewModel : MailBaseViewModel
public bool IsStartupBehaviorDisabled => !IsStartupBehaviorEnabled;
public bool IsStartupBehaviorEnabled => StartupBehaviorResult == StartupBehaviorResult.Enabled;
private string _selectedAppTerminationBehavior;
public string SelectedAppTerminationBehavior
{
get => _selectedAppTerminationBehavior;
set
{
SetProperty(ref _selectedAppTerminationBehavior, value);
PreferencesService.ServerTerminationBehavior = (ServerBackgroundMode)AppTerminationBehavior.IndexOf(value);
}
}
private string _selectedDefaultSearchMode;
public string SelectedDefaultSearchMode
{
@@ -66,35 +49,22 @@ public partial class AppPreferencesPageViewModel : MailBaseViewModel
}
private readonly IMailDialogService _dialogService;
private readonly IWinoServerConnectionManager _winoServerConnectionManager;
private readonly IStartupBehaviorService _startupBehaviorService;
public AppPreferencesPageViewModel(IMailDialogService dialogService,
IPreferencesService preferencesService,
IWinoServerConnectionManager winoServerConnectionManager,
IStartupBehaviorService startupBehaviorService)
{
_dialogService = dialogService;
PreferencesService = preferencesService;
_winoServerConnectionManager = winoServerConnectionManager;
_startupBehaviorService = startupBehaviorService;
// Load the app termination behavior options
_appTerminationBehavior =
[
Translator.SettingsAppPreferences_ServerBackgroundingMode_MinimizeTray_Title, // "Minimize to tray"
Translator.SettingsAppPreferences_ServerBackgroundingMode_Invisible_Title, // "Invisible"
Translator.SettingsAppPreferences_ServerBackgroundingMode_Terminate_Title // "Terminate"
];
SearchModes =
[
Translator.SettingsAppPreferences_SearchMode_Local,
Translator.SettingsAppPreferences_SearchMode_Online
];
SelectedAppTerminationBehavior = _appTerminationBehavior[(int)PreferencesService.ServerTerminationBehavior];
SelectedDefaultSearchMode = SearchModes[(int)PreferencesService.DefaultSearchMode];
EmailSyncIntervalMinutes = PreferencesService.EmailSyncIntervalMinutes;
}
@@ -152,20 +122,7 @@ public partial class AppPreferencesPageViewModel : MailBaseViewModel
}
}
protected override async void OnPropertyChanged(PropertyChangedEventArgs e)
{
base.OnPropertyChanged(e);
if (e.PropertyName == nameof(SelectedAppTerminationBehavior))
{
var terminationModeChangedResult = await _winoServerConnectionManager.GetResponseAsync<bool, ServerTerminationModeChanged>(new ServerTerminationModeChanged(PreferencesService.ServerTerminationBehavior));
if (!terminationModeChangedResult.IsSuccess)
{
_dialogService.InfoBarMessage(Translator.GeneralTitle_Error, terminationModeChangedResult.Message, InfoBarMessageType.Error);
}
}
}
public override async void OnNavigatedTo(NavigationMode mode, object parameters)
{
-18
View File
@@ -60,7 +60,6 @@ public partial class AppShellViewModel : MailBaseViewModel,
private const string IsActivateStartupLaunchAskedKey = nameof(IsActivateStartupLaunchAskedKey);
public IStatePersistanceService StatePersistenceService { get; }
public IWinoServerConnectionManager ServerConnectionManager { get; }
public IPreferencesService PreferencesService { get; }
public INavigationService NavigationService { get; }
@@ -81,9 +80,6 @@ public partial class AppShellViewModel : MailBaseViewModel,
private readonly SemaphoreSlim accountInitFolderUpdateSlim = new SemaphoreSlim(1);
[ObservableProperty]
private WinoServerConnectionStatus activeConnectionStatus;
public AppShellViewModel(IMailDialogService dialogService,
INavigationService navigationService,
IMimeFileService mimeFileService,
@@ -98,21 +94,10 @@ public partial class AppShellViewModel : MailBaseViewModel,
IWinoRequestDelegator winoRequestDelegator,
IFolderService folderService,
IStatePersistanceService statePersistanceService,
IWinoServerConnectionManager serverConnectionManager,
IConfigurationService configurationService,
IStartupBehaviorService startupBehaviorService)
{
StatePersistenceService = statePersistanceService;
ServerConnectionManager = serverConnectionManager;
ActiveConnectionStatus = serverConnectionManager.Status;
ServerConnectionManager.StatusChanged += async (sender, status) =>
{
await ExecuteUIThread(() =>
{
ActiveConnectionStatus = status;
});
};
PreferencesService = preferencesService;
_dialogService = dialogService;
@@ -132,9 +117,6 @@ public partial class AppShellViewModel : MailBaseViewModel,
_winoRequestDelegator = winoRequestDelegator;
}
[RelayCommand]
private Task ReconnectServerAsync() => ServerConnectionManager.ConnectAsync();
protected override void OnDispatcherAssigned()
{
base.OnDispatcherAssigned();
@@ -22,7 +22,6 @@ using Wino.Core.Domain.Models.Folders;
using Wino.Core.Domain.Models.MailItem;
using Wino.Core.Domain.Models.Menus;
using Wino.Core.Domain.Models.Reader;
using Wino.Core.Domain.Models.Server;
using Wino.Core.Domain.Models.Synchronization;
using Wino.Mail.ViewModels.Collections;
using Wino.Mail.ViewModels.Data;
@@ -23,13 +23,6 @@
</controls:SettingsCard.HeaderIcon>
</controls:SettingsCard>
<controls:SettingsCard Description="{x:Bind domain:Translator.SettingsAppPreferences_CloseBehavior_Description}" Header="{x:Bind domain:Translator.SettingsAppPreferences_CloseBehavior_Title}">
<ComboBox ItemsSource="{x:Bind ViewModel.AppTerminationBehavior, Mode=OneWay}" SelectedItem="{x:Bind ViewModel.SelectedAppTerminationBehavior, Mode=TwoWay}" />
<controls:SettingsCard.HeaderIcon>
<PathIcon Data="F1 M 1.591797 15.244141 C 1.591797 15.055339 1.635742 14.912109 1.723633 14.814453 C 1.811523 14.716797 1.930339 14.625651 2.080078 14.541016 C 2.26237 14.443359 2.457682 14.363607 2.666016 14.301758 C 2.874349 14.239909 3.072917 14.169922 3.261719 14.091797 C 3.834635 13.863933 4.394531 13.606771 4.941406 13.320312 C 5.488281 13.033854 6.005859 12.705078 6.494141 12.333984 C 7.106119 11.871745 7.643229 11.352539 8.105469 10.776367 C 8.567708 10.200195 8.95345 9.584961 9.262695 8.930664 C 9.571939 8.276367 9.804688 7.587891 9.960938 6.865234 C 10.117188 6.142578 10.195312 5.400391 10.195312 4.638672 C 10.195312 4.007162 10.144856 3.390301 10.043945 2.788086 C 9.943033 2.185873 9.830729 1.578777 9.707031 0.966797 C 9.700521 0.934246 9.695638 0.904949 9.692383 0.878906 C 9.689127 0.852865 9.6875 0.823568 9.6875 0.791016 C 9.6875 0.582684 9.759114 0.406902 9.902344 0.263672 C 10.045572 0.120443 10.221354 0.048828 10.429688 0.048828 C 10.800781 0.048828 11.183268 0.083008 11.577148 0.151367 C 11.971028 0.219727 12.361653 0.314129 12.749023 0.43457 C 13.136393 0.555014 13.515624 0.694988 13.886719 0.854492 C 14.257812 1.013998 14.602863 1.184896 14.921875 1.367188 C 15.690104 1.809896 16.383463 2.342123 17.001953 2.963867 C 17.620441 3.585613 18.144531 4.270834 18.574219 5.019531 C 19.003906 5.76823 19.334309 6.567384 19.56543 7.416992 C 19.796549 8.266602 19.912109 9.134115 19.912109 10.019531 C 19.912109 10.9375 19.793293 11.821289 19.555664 12.670898 C 19.318033 13.520508 18.981119 14.314779 18.544922 15.053711 C 18.108723 15.792644 17.587891 16.464844 16.982422 17.070312 C 16.376953 17.675781 15.703125 18.194986 14.960938 18.62793 C 14.21875 19.060873 13.422852 19.396158 12.573242 19.633789 C 11.723633 19.87142 10.839844 19.990234 9.921875 19.990234 C 9.140625 19.990234 8.352864 19.890951 7.558594 19.692383 C 6.764323 19.493814 6.005859 19.208984 5.283203 18.837891 C 4.560547 18.466797 3.891602 18.014322 3.276367 17.480469 C 2.661133 16.946615 2.141927 16.3444 1.71875 15.673828 C 1.634115 15.54362 1.591797 15.400391 1.591797 15.244141 Z M 9.921875 18.730469 C 10.722656 18.730469 11.495768 18.626303 12.241211 18.417969 C 12.986652 18.209635 13.683268 17.918295 14.331055 17.543945 C 14.978841 17.169598 15.568033 16.717123 16.098633 16.186523 C 16.62923 15.655925 17.084961 15.068359 17.46582 14.423828 C 17.84668 13.779297 18.141275 13.084311 18.349609 12.338867 C 18.557941 11.593425 18.662109 10.820312 18.662109 10.019531 C 18.662109 9.290365 18.575846 8.583984 18.40332 7.900391 C 18.230793 7.216798 17.983398 6.569012 17.661133 5.957031 C 17.338867 5.345053 16.951496 4.778646 16.499023 4.257812 C 16.046549 3.73698 15.538736 3.276367 14.975586 2.875977 C 14.412435 2.475586 13.802083 2.145184 13.144531 1.884766 C 12.486979 1.62435 11.796874 1.448568 11.074219 1.357422 C 11.184896 1.897787 11.274414 2.439779 11.342773 2.983398 C 11.411133 3.52702 11.445312 4.075521 11.445312 4.628906 C 11.445312 5.579428 11.336263 6.500652 11.118164 7.392578 C 10.900064 8.284506 10.569661 9.150391 10.126953 9.990234 C 9.749349 10.706381 9.309896 11.342773 8.808594 11.899414 C 8.307291 12.456055 7.758789 12.954102 7.163086 13.393555 C 6.567382 13.833008 5.929361 14.222006 5.249023 14.560547 C 4.568685 14.899089 3.863932 15.208334 3.134766 15.488281 C 3.544922 16.002604 4.005534 16.461588 4.516602 16.865234 C 5.027669 17.268881 5.574544 17.609049 6.157227 17.885742 C 6.739908 18.162436 7.348632 18.372396 7.983398 18.515625 C 8.618164 18.658854 9.264322 18.730469 9.921875 18.730469 Z " />
</controls:SettingsCard.HeaderIcon>
</controls:SettingsCard>
<controls:SettingsCard Description="{x:Bind domain:Translator.SettingsAppPreferences_SearchMode_Description}" Header="{x:Bind domain:Translator.SettingsAppPreferences_SearchMode_Title}">
<ComboBox ItemsSource="{x:Bind ViewModel.SearchModes, Mode=OneWay}" SelectedItem="{x:Bind ViewModel.SelectedDefaultSearchMode, Mode=TwoWay}" />
<controls:SettingsCard.HeaderIcon>
+7 -59
View File
@@ -52,18 +52,8 @@ public sealed partial class App : WinoApplication,
// We must restore it.
// Server might be running already, but re-launching it will trigger a new connection attempt.
try
{
await AppServiceConnectionManager.ConnectAsync();
}
catch (OperationCanceledException)
{
// Ignore
}
catch (Exception ex)
{
Log.Error(ex, "Failed to connect to server after resuming the app.");
}
// Server connection is now handled by the empty implementation
// No need to reconnect after resuming
}
public override IServiceProvider ConfigureServices()
@@ -137,13 +127,10 @@ public sealed partial class App : WinoApplication,
if (appServiceTriggerDetails.CallerPackageFamilyName == Package.Current.Id.FamilyName)
{
// Connection established from the fulltrust process
// This is no longer needed with the empty connection manager implementation
connectionBackgroundTaskDeferral = args.TaskInstance.GetDeferral();
args.TaskInstance.Canceled += OnConnectionBackgroundTaskCanceled;
AppServiceConnectionManager.Connection = appServiceTriggerDetails.AppServiceConnection;
WeakReferenceMessenger.Default.Send(new WinoServerConnectionEstablished());
}
}
else if (args.TaskInstance.TriggerDetails is ToastNotificationActionTriggerDetail toastNotificationActionTriggerDetail)
@@ -222,24 +209,13 @@ public sealed partial class App : WinoApplication,
connectionBackgroundTaskDeferral?.Complete();
connectionBackgroundTaskDeferral = null;
AppServiceConnectionManager.Connection = null;
}
public async void Receive(NewMailSynchronizationRequested message)
{
try
{
var synchronizationResultResponse = await AppServiceConnectionManager.GetResponseAsync<MailSynchronizationResult, NewMailSynchronizationRequested>(message);
synchronizationResultResponse.ThrowIfFailed();
}
catch (WinoServerException serverException)
{
// TODO: Exception context is lost.
var dialogService = Services.GetService<IMailDialogService>();
dialogService.InfoBarMessage(Translator.Info_SyncFailedTitle, serverException.Message, InfoBarMessageType.Error);
}
// Synchronization is now handled elsewhere
// The empty connection manager doesn't perform actual sync operations
await Task.CompletedTask;
}
protected override async void OnApplicationCloseRequested(object sender, SystemNavigationCloseRequestedPreviewEventArgs e)
@@ -262,20 +238,7 @@ public sealed partial class App : WinoApplication,
bool? isGoToAppPreferencesRequested = null;
if (preferencesService.ServerTerminationBehavior == ServerBackgroundMode.Terminate)
{
// Starting the server is fine, but check if server termination behavior is set to terminate.
// This state will kill the server once the app is terminated.
isGoToAppPreferencesRequested = await dialogService.ShowWinoCustomMessageDialogAsync(Translator.AppCloseBackgroundSynchronizationWarningTitle,
$"{Translator.AppCloseTerminateBehaviorWarningMessageFirstLine}\n{Translator.AppCloseTerminateBehaviorWarningMessageSecondLine}\n\n{Translator.AppCloseTerminateBehaviorWarningMessageThirdLine}",
Translator.Buttons_Yes,
WinoCustomMessageDialogIcon.Warning,
Translator.Buttons_No,
"DontAskTerminateServerBehavior");
}
if (isGoToAppPreferencesRequested == null && currentStartupBehavior != StartupBehaviorResult.Enabled)
if (currentStartupBehavior != StartupBehaviorResult.Enabled)
{
// Startup behavior is not enabled.
@@ -292,21 +255,6 @@ public sealed partial class App : WinoApplication,
WeakReferenceMessenger.Default.Send(new NavigateAppPreferencesRequested());
e.Handled = true;
}
else if (preferencesService.ServerTerminationBehavior == ServerBackgroundMode.Terminate)
{
try
{
var isServerKilled = await AppServiceConnectionManager.GetResponseAsync<bool, TerminateServerRequested>(new TerminateServerRequested());
isServerKilled.ThrowIfFailed();
Log.Information("Server is killed.");
}
catch (Exception ex)
{
Log.Error(ex, "Failed to kill server.");
}
}
deferral.Complete();
}
-2
View File
@@ -457,7 +457,6 @@
Grid.ColumnSpan="2"
BackButtonClicked="BackButtonClicked"
Canvas.ZIndex="150"
ConnectionStatus="{x:Bind ViewModel.ActiveConnectionStatus, Mode=OneWay}"
CoreWindowText="{x:Bind ViewModel.StatePersistenceService.CoreWindowTitle, Mode=OneWay}"
IsBackButtonVisible="{x:Bind ViewModel.StatePersistenceService.IsBackButtonVisible, Mode=OneWay}"
IsDragArea="True"
@@ -466,7 +465,6 @@
NavigationViewDisplayMode="{x:Bind navigationView.DisplayMode, Mode=OneWay}"
OpenPaneLength="{x:Bind ViewModel.StatePersistenceService.OpenPaneLength, Mode=OneWay}"
ReadingPaneLength="{x:Bind ViewModel.StatePersistenceService.MailListPaneLength, Mode=OneWay}"
ReconnectCommand="{x:Bind ViewModel.ReconnectServerCommand}"
SystemReserved="180" />
</Grid>
</abstract:AppShellAbstract>
@@ -23,13 +23,6 @@
</controls:SettingsCard.HeaderIcon>
</controls:SettingsCard>
<controls:SettingsCard Description="{x:Bind domain:Translator.SettingsAppPreferences_CloseBehavior_Description}" Header="{x:Bind domain:Translator.SettingsAppPreferences_CloseBehavior_Title}">
<ComboBox ItemsSource="{x:Bind ViewModel.AppTerminationBehavior, Mode=OneWay}" SelectedItem="{x:Bind ViewModel.SelectedAppTerminationBehavior, Mode=TwoWay}" />
<controls:SettingsCard.HeaderIcon>
<PathIcon Data="F1 M 1.591797 15.244141 C 1.591797 15.055339 1.635742 14.912109 1.723633 14.814453 C 1.811523 14.716797 1.930339 14.625651 2.080078 14.541016 C 2.26237 14.443359 2.457682 14.363607 2.666016 14.301758 C 2.874349 14.239909 3.072917 14.169922 3.261719 14.091797 C 3.834635 13.863933 4.394531 13.606771 4.941406 13.320312 C 5.488281 13.033854 6.005859 12.705078 6.494141 12.333984 C 7.106119 11.871745 7.643229 11.352539 8.105469 10.776367 C 8.567708 10.200195 8.95345 9.584961 9.262695 8.930664 C 9.571939 8.276367 9.804688 7.587891 9.960938 6.865234 C 10.117188 6.142578 10.195312 5.400391 10.195312 4.638672 C 10.195312 4.007162 10.144856 3.390301 10.043945 2.788086 C 9.943033 2.185873 9.830729 1.578777 9.707031 0.966797 C 9.700521 0.934246 9.695638 0.904949 9.692383 0.878906 C 9.689127 0.852865 9.6875 0.823568 9.6875 0.791016 C 9.6875 0.582684 9.759114 0.406902 9.902344 0.263672 C 10.045572 0.120443 10.221354 0.048828 10.429688 0.048828 C 10.800781 0.048828 11.183268 0.083008 11.577148 0.151367 C 11.971028 0.219727 12.361653 0.314129 12.749023 0.43457 C 13.136393 0.555014 13.515624 0.694988 13.886719 0.854492 C 14.257812 1.013998 14.602863 1.184896 14.921875 1.367188 C 15.690104 1.809896 16.383463 2.342123 17.001953 2.963867 C 17.620441 3.585613 18.144531 4.270834 18.574219 5.019531 C 19.003906 5.76823 19.334309 6.567384 19.56543 7.416992 C 19.796549 8.266602 19.912109 9.134115 19.912109 10.019531 C 19.912109 10.9375 19.793293 11.821289 19.555664 12.670898 C 19.318033 13.520508 18.981119 14.314779 18.544922 15.053711 C 18.108723 15.792644 17.587891 16.464844 16.982422 17.070312 C 16.376953 17.675781 15.703125 18.194986 14.960938 18.62793 C 14.21875 19.060873 13.422852 19.396158 12.573242 19.633789 C 11.723633 19.87142 10.839844 19.990234 9.921875 19.990234 C 9.140625 19.990234 8.352864 19.890951 7.558594 19.692383 C 6.764323 19.493814 6.005859 19.208984 5.283203 18.837891 C 4.560547 18.466797 3.891602 18.014322 3.276367 17.480469 C 2.661133 16.946615 2.141927 16.3444 1.71875 15.673828 C 1.634115 15.54362 1.591797 15.400391 1.591797 15.244141 Z M 9.921875 18.730469 C 10.722656 18.730469 11.495768 18.626303 12.241211 18.417969 C 12.986652 18.209635 13.683268 17.918295 14.331055 17.543945 C 14.978841 17.169598 15.568033 16.717123 16.098633 16.186523 C 16.62923 15.655925 17.084961 15.068359 17.46582 14.423828 C 17.84668 13.779297 18.141275 13.084311 18.349609 12.338867 C 18.557941 11.593425 18.662109 10.820312 18.662109 10.019531 C 18.662109 9.290365 18.575846 8.583984 18.40332 7.900391 C 18.230793 7.216798 17.983398 6.569012 17.661133 5.957031 C 17.338867 5.345053 16.951496 4.778646 16.499023 4.257812 C 16.046549 3.73698 15.538736 3.276367 14.975586 2.875977 C 14.412435 2.475586 13.802083 2.145184 13.144531 1.884766 C 12.486979 1.62435 11.796874 1.448568 11.074219 1.357422 C 11.184896 1.897787 11.274414 2.439779 11.342773 2.983398 C 11.411133 3.52702 11.445312 4.075521 11.445312 4.628906 C 11.445312 5.579428 11.336263 6.500652 11.118164 7.392578 C 10.900064 8.284506 10.569661 9.150391 10.126953 9.990234 C 9.749349 10.706381 9.309896 11.342773 8.808594 11.899414 C 8.307291 12.456055 7.758789 12.954102 7.163086 13.393555 C 6.567382 13.833008 5.929361 14.222006 5.249023 14.560547 C 4.568685 14.899089 3.863932 15.208334 3.134766 15.488281 C 3.544922 16.002604 4.005534 16.461588 4.516602 16.865234 C 5.027669 17.268881 5.574544 17.609049 6.157227 17.885742 C 6.739908 18.162436 7.348632 18.372396 7.983398 18.515625 C 8.618164 18.658854 9.264322 18.730469 9.921875 18.730469 Z " />
</controls:SettingsCard.HeaderIcon>
</controls:SettingsCard>
<controls:SettingsCard Description="{x:Bind domain:Translator.SettingsAppPreferences_SearchMode_Description}" Header="{x:Bind domain:Translator.SettingsAppPreferences_SearchMode_Title}">
<ComboBox ItemsSource="{x:Bind ViewModel.SearchModes, Mode=OneWay}" SelectedItem="{x:Bind ViewModel.SelectedDefaultSearchMode, Mode=TwoWay}" />
<controls:SettingsCard.HeaderIcon>
@@ -1,10 +0,0 @@
using Wino.Core.Domain.Enums;
using Wino.Core.Domain.Interfaces;
namespace Wino.Messaging.Server;
/// <summary>
/// App close behavior for server is changed.
/// </summary>
/// <param name="ServerBackgroundMode">New server background mode.</param>
public record ServerTerminationModeChanged(ServerBackgroundMode ServerBackgroundMode) : IClientMessage;