Remove connection manager.
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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>();
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
Reference in New Issue
Block a user