2025-09-29 19:09:48 +02:00
using System ;
2026-02-07 14:03:41 +01:00
using System.Collections.ObjectModel ;
using System.Linq ;
2026-02-11 01:49:29 +01:00
using System.Threading.Tasks ;
2025-10-21 15:40:19 +02:00
using CommunityToolkit.Mvvm.Input ;
2025-09-29 19:09:48 +02:00
using CommunityToolkit.Mvvm.Messaging ;
using Microsoft.Extensions.DependencyInjection ;
2025-09-29 11:16:14 +02:00
using Microsoft.UI.Xaml ;
using Microsoft.UI.Xaml.Controls ;
2025-10-04 13:40:35 +02:00
using Windows.UI ;
2026-02-07 14:03:41 +01:00
using Wino.Core.Domain ;
2026-03-16 01:33:27 +01:00
using Wino.Core.Domain.Entities.Shared ;
2026-02-22 15:13:39 +01:00
using Wino.Core.Domain.Enums ;
2025-09-29 19:09:48 +02:00
using Wino.Core.Domain.Interfaces ;
2026-02-07 14:03:41 +01:00
using Wino.Core.Domain.Models.Synchronization ;
2026-03-07 23:33:25 +01:00
using Wino.Extensions ;
2026-02-22 15:13:39 +01:00
using Wino.Mail.WinUI.Activation ;
2026-03-16 01:33:27 +01:00
using Wino.Mail.WinUI.Extensions ;
2025-11-15 14:52:01 +01:00
using Wino.Mail.WinUI.Interfaces ;
2026-03-25 09:45:49 +01:00
using Wino.Mail.WinUI.Models ;
2026-03-11 01:39:32 +01:00
using Wino.Mail.WinUI.Views ;
2025-10-04 13:40:35 +02:00
using Wino.Messaging.Client.Shell ;
2025-10-03 22:12:27 +02:00
using Wino.Messaging.UI ;
2025-09-29 11:16:14 +02:00
using WinUIEx ;
namespace Wino.Mail.WinUI ;
2026-02-07 14:03:41 +01:00
public sealed partial class ShellWindow : WindowEx , IWinoShellWindow ,
IRecipient < ApplicationThemeChanged > ,
2026-03-07 23:33:25 +01:00
IRecipient < InfoBarMessageRequested > ,
2026-02-07 14:03:41 +01:00
IRecipient < TitleBarShellContentUpdated > ,
IRecipient < SynchronizationActionsAdded > ,
2026-03-16 01:33:27 +01:00
IRecipient < SynchronizationActionsCompleted > ,
2026-03-19 10:26:17 +01:00
IRecipient < WinoAccountProfileUpdatedMessage > ,
IRecipient < WinoAccountProfileDeletedMessage >
2025-09-29 11:16:14 +02:00
{
2026-03-27 14:45:36 +01:00
private bool _allowClose ;
2025-09-29 19:09:48 +02:00
public IStatePersistanceService StatePersistanceService { get ; } = WinoApplication . Current . Services . GetService < IStatePersistanceService > ( ) ? ? throw new Exception ( "StatePersistanceService not registered in DI container." ) ;
public IPreferencesService PreferencesService { get ; } = WinoApplication . Current . Services . GetService < IPreferencesService > ( ) ? ? throw new Exception ( "PreferencesService not registered in DI container." ) ;
2025-12-26 20:46:48 +01:00
public INavigationService NavigationService { get ; } = WinoApplication . Current . Services . GetService < INavigationService > ( ) ? ? throw new Exception ( "NavigationService not registered in DI container." ) ;
2026-03-16 01:33:27 +01:00
private IMailDialogService MailDialogService { get ; } = WinoApplication . Current . Services . GetRequiredService < IMailDialogService > ( ) ;
private IWinoAccountProfileService WinoAccountProfileService { get ; } = WinoApplication . Current . Services . GetRequiredService < IWinoAccountProfileService > ( ) ;
2025-10-21 15:40:19 +02:00
2026-02-07 14:03:41 +01:00
public ObservableCollection < SynchronizationActionItem > SyncActionItems { get ; } = new ( ) ;
2026-02-11 01:49:29 +01:00
private bool _calendarReminderServerStartAttempted ;
2026-03-25 09:45:49 +01:00
private ITitleBarSearchHost ? _activeTitleBarSearchHost ;
2026-03-24 18:05:09 +01:00
private bool _isBackButtonVisibilityReady ;
2026-03-25 09:45:49 +01:00
private bool _isSynchronizingTitleBarSearch ;
2026-02-07 14:03:41 +01:00
2025-09-29 11:16:14 +02:00
public ShellWindow ( )
{
2025-10-21 01:27:29 +02:00
RegisterRecipients ( ) ;
2025-10-03 22:12:27 +02:00
2025-09-29 11:16:14 +02:00
InitializeComponent ( ) ;
2026-03-24 18:05:09 +01:00
StatePersistanceService . StatePropertyChanged + = StatePersistenceServiceChanged ;
2025-09-29 11:16:14 +02:00
2025-09-29 19:09:48 +02:00
MinWidth = 420 ;
MinHeight = 420 ;
2025-09-29 11:16:14 +02:00
ConfigureTitleBar ( ) ;
2026-03-25 09:45:49 +01:00
ApplyTitleBarSearchHost ( ) ;
2025-10-04 15:46:05 +02:00
// Handle window closing event to minimize to tray instead of closing
Closed + = OnWindowClosed ;
// Use the AppWindow.Closing event to handle the close request
AppWindow . Closing + = OnAppWindowClosing ;
2025-10-21 15:40:19 +02:00
2026-01-06 17:34:06 +01:00
// Register global mouse button listener for back button
RegisterMouseBackButtonListener ( ) ;
2025-10-31 19:53:43 +01:00
this . SetIcon ( "Assets/Wino_Icon.ico" ) ;
2026-03-09 00:28:10 +01:00
Title = StatePersistanceService . AppModeTitle ;
2025-09-29 11:16:14 +02:00
}
private void ConfigureTitleBar ( )
{
AppWindow . TitleBar . ExtendsContentIntoTitleBar = true ;
2025-10-21 15:40:19 +02:00
2025-10-04 13:40:35 +02:00
// Apply initial theme colors
var themeService = WinoApplication . Current . Services . GetService < INewThemeService > ( ) ;
if ( themeService ! = null )
{
var underlyingThemeService = WinoApplication . Current . Services . GetService < IUnderlyingThemeService > ( ) ;
if ( underlyingThemeService ! = null )
{
UpdateTitleBarColors ( underlyingThemeService . IsUnderlyingThemeDark ( ) ) ;
}
}
2025-09-29 11:16:14 +02:00
}
2026-01-06 17:34:06 +01:00
private void RegisterMouseBackButtonListener ( )
{
// Subscribe to pointer pressed events on the root content
if ( Content is UIElement rootElement )
{
rootElement . AddHandler ( UIElement . PointerPressedEvent , new Microsoft . UI . Xaml . Input . PointerEventHandler ( OnPointerPressed ) , true ) ;
}
}
private void OnPointerPressed ( object sender , Microsoft . UI . Xaml . Input . PointerRoutedEventArgs e )
{
// Check if it's the back button (XButton1)
var pointerPoint = e . GetCurrentPoint ( null ) ;
var properties = pointerPoint . Properties ;
// XButton1 is the back button on most mice
if ( properties . IsXButton1Pressed )
{
// Call GoBack on NavigationService
NavigationService . GoBack ( ) ;
e . Handled = true ;
}
}
2026-02-22 15:13:39 +01:00
public void HandleAppActivation ( string? launchArguments , string? tileId = null , string? appId = null )
2025-09-29 11:16:14 +02:00
{
2026-02-22 17:55:57 +01:00
var targetMode = AppModeActivationResolver . Resolve ( launchArguments , tileId , appId , PreferencesService . DefaultApplicationMode ) ;
2026-02-22 15:13:39 +01:00
NavigationService . ChangeApplicationMode ( targetMode ) ;
2025-09-29 11:16:14 +02:00
}
public Microsoft . UI . Xaml . Controls . TitleBar GetTitleBar ( ) = > ShellTitleBar ;
public Frame GetMainFrame ( ) = > MainShellFrame ;
2025-09-29 19:09:48 +02:00
public FrameworkElement GetRootContent ( ) = > Content as Grid ? ? throw new Exception ( "RootContent is not a Grid or empty." ) ;
private void BackButtonClicked ( Microsoft . UI . Xaml . Controls . TitleBar sender , object args )
{
2025-12-29 14:10:09 +01:00
NavigationService . GoBack ( ) ;
2025-09-29 19:09:48 +02:00
}
2025-11-14 18:51:48 +01:00
private void MainFrameNavigated ( object sender , Microsoft . UI . Xaml . Navigation . NavigationEventArgs e )
{
2026-02-11 01:49:29 +01:00
if ( ! _calendarReminderServerStartAttempted )
{
_calendarReminderServerStartAttempted = true ;
_ = StartCalendarReminderServerAsync ( ) ;
}
2026-03-24 18:05:09 +01:00
_isBackButtonVisibilityReady = true ;
2026-03-25 09:45:49 +01:00
ApplyTitleBarSearchHost ( ) ;
2026-03-24 18:05:09 +01:00
RefreshBackButtonVisibility ( ) ;
2025-11-14 18:51:48 +01:00
}
2025-09-29 19:09:48 +02:00
2026-02-11 01:49:29 +01:00
private async Task StartCalendarReminderServerAsync ( )
{
try
{
var reminderServer = WinoApplication . Current . Services . GetService < ICalendarReminderServer > ( ) ;
if ( reminderServer ! = null )
{
await reminderServer . StartAsync ( ) ;
}
}
catch ( Exception ex )
{
_calendarReminderServerStartAttempted = false ;
Serilog . Log . Error ( ex , "Failed to start calendar reminder server." ) ;
}
}
2025-09-29 19:09:48 +02:00
private void PaneButtonClicked ( Microsoft . UI . Xaml . Controls . TitleBar sender , object args )
{
PreferencesService . IsNavigationPaneOpened = ! PreferencesService . IsNavigationPaneOpened ;
}
2025-10-03 22:12:27 +02:00
public void Receive ( TitleBarShellContentUpdated message )
{
2026-03-25 09:45:49 +01:00
ApplyTitleBarSearchHost ( ) ;
2026-03-24 18:05:09 +01:00
RefreshBackButtonVisibility ( ) ;
2025-10-03 22:12:27 +02:00
}
2025-10-04 13:40:35 +02:00
public void Receive ( ApplicationThemeChanged message )
{
UpdateTitleBarColors ( message . IsUnderlyingThemeDark ) ;
}
2026-03-07 23:33:25 +01:00
public void Receive ( InfoBarMessageRequested message )
{
2026-03-16 01:33:27 +01:00
ShowInfoBarMessage ( message ) ;
2026-03-07 23:33:25 +01:00
}
2026-02-07 14:03:41 +01:00
public void Receive ( SynchronizationActionsAdded message )
{
DispatcherQueue . TryEnqueue ( ( ) = >
{
foreach ( var action in message . Actions )
SyncActionItems . Add ( action ) ;
UpdateSyncStatusVisibility ( ) ;
} ) ;
}
public void Receive ( SynchronizationActionsCompleted message )
{
DispatcherQueue . TryEnqueue ( ( ) = >
{
var toRemove = SyncActionItems . Where ( a = > a . AccountId = = message . AccountId ) . ToList ( ) ;
foreach ( var item in toRemove )
SyncActionItems . Remove ( item ) ;
UpdateSyncStatusVisibility ( ) ;
} ) ;
}
2026-03-19 10:26:17 +01:00
public void Receive ( WinoAccountProfileUpdatedMessage message )
2026-03-16 01:33:27 +01:00
{
DispatcherQueue . TryEnqueue ( ( ) = > UpdateWinoAccountState ( message . Account ) ) ;
}
2026-03-19 10:26:17 +01:00
public void Receive ( WinoAccountProfileDeletedMessage message )
2026-03-16 01:33:27 +01:00
{
DispatcherQueue . TryEnqueue ( ( ) = > UpdateWinoAccountState ( null ) ) ;
}
2026-02-07 14:03:41 +01:00
private void UpdateSyncStatusVisibility ( )
{
SyncStatusButton . Visibility = SyncActionItems . Any ( )
? Visibility . Visible
: Visibility . Collapsed ;
var distinctAccounts = SyncActionItems . Select ( a = > a . AccountId ) . Distinct ( ) . Count ( ) ;
SyncStatusText . Text = distinctAccounts switch
{
0 = > string . Empty ,
1 = > string . Format ( Translator . SyncAction_SynchronizingAccount , SyncActionItems . First ( ) . AccountName ) ,
_ = > string . Format ( Translator . SyncAction_SynchronizingAccounts , distinctAccounts )
} ;
}
2025-10-04 13:40:35 +02:00
private void UpdateTitleBarColors ( bool isDarkTheme )
{
DispatcherQueue . TryEnqueue ( ( ) = >
{
var titleBar = AppWindow . TitleBar ;
if ( titleBar = = null ) return ;
// Set button colors based on theme
// Background is always transparent for all buttons
titleBar . ButtonBackgroundColor = Color . FromArgb ( 0 , 0 , 0 , 0 ) ; // Transparent
titleBar . ButtonInactiveBackgroundColor = Color . FromArgb ( 0 , 0 , 0 , 0 ) ; // Transparent
titleBar . ButtonHoverBackgroundColor = Color . FromArgb ( 0 , 0 , 0 , 0 ) ; // Transparent
titleBar . ButtonPressedBackgroundColor = Color . FromArgb ( 0 , 0 , 0 , 0 ) ; // Transparent
if ( isDarkTheme )
{
// Dark theme: use light text/icons for better contrast
titleBar . ButtonForegroundColor = Color . FromArgb ( 255 , 255 , 255 , 255 ) ; // White
titleBar . ButtonInactiveForegroundColor = Color . FromArgb ( 128 , 255 , 255 , 255 ) ; // Semi-transparent white
titleBar . ButtonHoverForegroundColor = Color . FromArgb ( 255 , 255 , 255 , 255 ) ; // White
titleBar . ButtonPressedForegroundColor = Color . FromArgb ( 200 , 255 , 255 , 255 ) ; // Slightly dimmed white
}
else
{
// Light theme: use dark text/icons for better contrast
titleBar . ButtonForegroundColor = Color . FromArgb ( 255 , 0 , 0 , 0 ) ; // Black
titleBar . ButtonInactiveForegroundColor = Color . FromArgb ( 128 , 0 , 0 , 0 ) ; // Semi-transparent black
titleBar . ButtonHoverForegroundColor = Color . FromArgb ( 255 , 0 , 0 , 0 ) ; // Black
titleBar . ButtonPressedForegroundColor = Color . FromArgb ( 200 , 0 , 0 , 0 ) ; // Slightly dimmed black
}
} ) ;
}
2025-10-04 15:46:05 +02:00
2026-03-25 09:45:49 +01:00
private void ApplyTitleBarSearchHost ( )
2026-03-24 16:57:13 +01:00
{
2026-03-25 09:45:49 +01:00
_activeTitleBarSearchHost = ResolveActiveTitleBarSearchHost ( ) ;
SynchronizeTitleBarSearchBox ( ) ;
2026-03-24 18:05:09 +01:00
}
private void StatePersistenceServiceChanged ( object? sender , string propertyName )
{
if ( ! DispatcherQueue . HasThreadAccess )
{
var enqueued = DispatcherQueue . TryEnqueue ( ( ) = > StatePersistenceServiceChanged ( sender , propertyName ) ) ;
if ( ! enqueued )
throw new InvalidOperationException ( "Could not marshal shell state changes onto the UI thread." ) ;
return ;
}
if ( propertyName = = nameof ( IStatePersistanceService . ApplicationMode ) | |
propertyName = = nameof ( IStatePersistanceService . IsReadingMail ) | |
propertyName = = nameof ( IStatePersistanceService . IsReaderNarrowed ) | |
propertyName = = nameof ( IStatePersistanceService . IsEventDetailsVisible ) )
{
RefreshBackButtonVisibility ( ) ;
}
}
private void RefreshBackButtonVisibility ( )
{
if ( ! _isBackButtonVisibilityReady )
{
ShellTitleBar . IsBackButtonVisible = false ;
return ;
}
ShellTitleBar . IsBackButtonVisible = NavigationService . CanGoBack ( ) ;
2026-03-24 16:57:13 +01:00
}
2026-03-25 09:45:49 +01:00
private ITitleBarSearchHost ? ResolveActiveTitleBarSearchHost ( )
2026-03-24 16:57:13 +01:00
{
2026-03-25 09:45:49 +01:00
if ( MainShellFrame . Content is WinoAppShell shellPage )
2026-03-24 16:57:13 +01:00
{
2026-03-25 09:45:49 +01:00
return shellPage . GetShellFrame ( ) . Content as ITitleBarSearchHost ;
2026-03-24 16:57:13 +01:00
}
2026-03-25 09:45:49 +01:00
return MainShellFrame . Content as ITitleBarSearchHost ;
2026-03-24 16:57:13 +01:00
}
2026-03-25 09:45:49 +01:00
private void SynchronizeTitleBarSearchBox ( )
2026-03-24 16:57:13 +01:00
{
2026-03-25 09:45:49 +01:00
_isSynchronizingTitleBarSearch = true ;
try
2026-03-24 16:57:13 +01:00
{
2026-03-25 09:45:49 +01:00
TitleBarSearchBox . IsEnabled = _activeTitleBarSearchHost ! = null ;
TitleBarSearchBox . PlaceholderText = _activeTitleBarSearchHost ? . SearchPlaceholderText ? ? Translator . SearchBarPlaceholder ;
TitleBarSearchBox . ItemsSource = _activeTitleBarSearchHost ? . SearchSuggestions ;
TitleBarSearchBox . Text = _activeTitleBarSearchHost ? . SearchText ? ? string . Empty ;
2026-03-24 16:57:13 +01:00
}
2026-03-25 09:45:49 +01:00
finally
2026-03-24 16:57:13 +01:00
{
2026-03-25 09:45:49 +01:00
_isSynchronizingTitleBarSearch = false ;
2026-03-24 16:57:13 +01:00
}
}
2026-03-25 09:45:49 +01:00
private async void TitleBarSearchTextChanged ( AutoSuggestBox sender , AutoSuggestBoxTextChangedEventArgs args )
2026-03-24 16:57:13 +01:00
{
2026-03-25 09:45:49 +01:00
if ( _isSynchronizingTitleBarSearch | | _activeTitleBarSearchHost = = null )
2026-03-24 16:57:13 +01:00
return ;
2026-03-25 09:45:49 +01:00
_activeTitleBarSearchHost . SearchText = sender . Text ;
await _activeTitleBarSearchHost . OnTitleBarSearchTextChangedAsync ( ) ;
2026-03-24 16:57:13 +01:00
}
2026-03-25 09:45:49 +01:00
private void TitleBarSearchSuggestionChosen ( AutoSuggestBox sender , AutoSuggestBoxSuggestionChosenEventArgs args )
2026-03-24 16:57:13 +01:00
{
2026-03-25 09:45:49 +01:00
if ( _activeTitleBarSearchHost = = null | | args . SelectedItem is not TitleBarSearchSuggestion suggestion )
2026-03-24 16:57:13 +01:00
return ;
2026-03-25 09:45:49 +01:00
_activeTitleBarSearchHost . OnTitleBarSearchSuggestionChosen ( suggestion ) ;
SynchronizeTitleBarSearchBox ( ) ;
2026-03-24 16:57:13 +01:00
}
2026-03-25 09:45:49 +01:00
private async void TitleBarSearchQuerySubmitted ( AutoSuggestBox sender , AutoSuggestBoxQuerySubmittedEventArgs args )
{
if ( _activeTitleBarSearchHost = = null )
return ;
2026-03-24 16:57:13 +01:00
2026-03-25 09:45:49 +01:00
await _activeTitleBarSearchHost . OnTitleBarSearchSubmittedAsync ( args . QueryText , args . ChosenSuggestion as TitleBarSearchSuggestion ) ;
SynchronizeTitleBarSearchBox ( ) ;
}
2026-03-24 16:57:13 +01:00
2025-10-04 15:46:05 +02:00
private void OnAppWindowClosing ( object sender , Microsoft . UI . Windowing . AppWindowClosingEventArgs e )
{
2026-03-27 14:45:36 +01:00
if ( _allowClose | | ( Application . Current as App ) ? . IsExiting = = true )
2026-03-20 12:43:09 +01:00
return ;
2025-10-04 15:46:05 +02:00
e . Cancel = true ;
2026-03-20 12:43:09 +01:00
var windowManager = WinoApplication . Current . Services . GetService < IWinoWindowManager > ( ) ;
windowManager ? . HideWindow ( this ) ;
2025-10-04 15:46:05 +02:00
}
2026-03-27 14:45:36 +01:00
public void PrepareForClose ( )
{
if ( MainShellFrame . Content is WinoAppShell shellPage )
{
shellPage . PrepareForWindowClose ( ) ;
}
_allowClose = true ;
}
2025-10-04 15:46:05 +02:00
private void OnWindowClosed ( object sender , WindowEventArgs e )
{
2026-03-27 14:45:36 +01:00
Closed - = OnWindowClosed ;
2025-10-04 15:46:05 +02:00
AppWindow . Closing - = OnAppWindowClosing ;
2026-03-24 18:05:09 +01:00
StatePersistanceService . StatePropertyChanged - = StatePersistenceServiceChanged ;
2026-03-27 14:45:36 +01:00
if ( MainShellFrame . Content is WinoAppShell shellPage )
{
shellPage . PrepareForWindowClose ( ) ;
}
2025-10-21 01:27:29 +02:00
UnregisterRecipients ( ) ;
2025-10-04 15:46:05 +02:00
}
2025-10-21 01:27:29 +02:00
private void RegisterRecipients ( )
{
WeakReferenceMessenger . Default . Register < TitleBarShellContentUpdated > ( this ) ;
WeakReferenceMessenger . Default . Register < ApplicationThemeChanged > ( this ) ;
2026-03-07 23:33:25 +01:00
WeakReferenceMessenger . Default . Register < InfoBarMessageRequested > ( this ) ;
2026-02-07 14:03:41 +01:00
WeakReferenceMessenger . Default . Register < SynchronizationActionsAdded > ( this ) ;
WeakReferenceMessenger . Default . Register < SynchronizationActionsCompleted > ( this ) ;
2026-03-19 10:26:17 +01:00
WeakReferenceMessenger . Default . Register < WinoAccountProfileUpdatedMessage > ( this ) ;
WeakReferenceMessenger . Default . Register < WinoAccountProfileDeletedMessage > ( this ) ;
2025-10-21 01:27:29 +02:00
}
private void UnregisterRecipients ( )
{
WeakReferenceMessenger . Default . Unregister < TitleBarShellContentUpdated > ( this ) ;
WeakReferenceMessenger . Default . Unregister < ApplicationThemeChanged > ( this ) ;
2026-03-07 23:33:25 +01:00
WeakReferenceMessenger . Default . Unregister < InfoBarMessageRequested > ( this ) ;
2026-02-07 14:03:41 +01:00
WeakReferenceMessenger . Default . Unregister < SynchronizationActionsAdded > ( this ) ;
WeakReferenceMessenger . Default . Unregister < SynchronizationActionsCompleted > ( this ) ;
2026-03-19 10:26:17 +01:00
WeakReferenceMessenger . Default . Unregister < WinoAccountProfileUpdatedMessage > ( this ) ;
WeakReferenceMessenger . Default . Unregister < WinoAccountProfileDeletedMessage > ( this ) ;
2026-03-16 01:33:27 +01:00
}
private void ShowInfoBarMessage ( InfoBarMessageRequested message )
{
DispatcherQueue . TryEnqueue ( ( ) = >
{
if ( string . IsNullOrEmpty ( message . ActionButtonTitle ) | | message . Action = = null )
{
ShellInfoBar . ActionButton = null ;
}
else
{
ShellInfoBar . ActionButton = new Button ( )
{
Content = message . ActionButtonTitle ,
Command = new RelayCommand ( message . Action )
} ;
}
ShellInfoBar . Message = message . Message ;
ShellInfoBar . Title = message . Title ;
ShellInfoBar . Severity = message . Severity . AsMUXCInfoBarSeverity ( ) ;
ShellInfoBar . IsOpen = true ;
} ) ;
}
private void UpdateWinoAccountState ( WinoAccount ? account )
{
var isSignedIn = account ! = null ;
WinoAccountSignedOutView . Visibility = isSignedIn ? Visibility . Collapsed : Visibility . Visible ;
WinoAccountSignedInView . Visibility = isSignedIn ? Visibility . Visible : Visibility . Collapsed ;
2026-03-17 17:47:45 +01:00
WinoAccountButtonPicture . Visibility = isSignedIn ? Visibility . Visible : Visibility . Collapsed ;
WinoAccountSignedOutIcon . Visibility = isSignedIn ? Visibility . Collapsed : Visibility . Visible ;
2026-03-16 01:33:27 +01:00
var initials = GetInitials ( account ? . Email ) ;
WinoAccountButtonPicture . Initials = initials ;
WinoAccountFlyoutPicture . Initials = initials ;
WinoAccountButtonPicture . DisplayName = account ? . Email ? ? Translator . WinoAccount_Titlebar_SignedOutTitle ;
WinoAccountFlyoutPicture . DisplayName = account ? . Email ? ? Translator . WinoAccount_Titlebar_SignedOutTitle ;
WinoAccountFlyoutEmailText . Text = account ? . Email ? ? string . Empty ;
WinoAccountFlyoutStatusText . Text = account = = null
? string . Empty
: string . Format ( Translator . WinoAccount_Titlebar_SignedInStatus , account . AccountStatus ) ;
}
private static string GetInitials ( string? email )
{
if ( string . IsNullOrWhiteSpace ( email ) )
{
return "W" ;
}
var localPart = email . Split ( '@' ) [ 0 ] ;
var segments = localPart
. Split ( [ '.' , '_' , '-' , ' ' ] , StringSplitOptions . RemoveEmptyEntries )
. Where ( segment = > ! string . IsNullOrWhiteSpace ( segment ) )
. Take ( 2 )
. ToArray ( ) ;
if ( segments . Length = = 0 )
{
return email [ . . 1 ] . ToUpperInvariant ( ) ;
}
return string . Concat ( segments . Select ( segment = > char . ToUpperInvariant ( segment [ 0 ] ) ) ) ;
}
private async void RegisterWinoAccountClicked ( object sender , RoutedEventArgs e )
{
2026-03-16 15:02:39 +01:00
WinoAccountFlyout . Hide ( ) ;
2026-03-16 01:33:27 +01:00
var account = await MailDialogService . ShowWinoAccountRegistrationDialogAsync ( ) ;
if ( account ! = null )
{
ShowInfoBarMessage ( new InfoBarMessageRequested (
InfoBarMessageType . Success ,
Translator . GeneralTitle_Info ,
string . Format ( Translator . WinoAccount_RegisterSuccessMessage , account . Email ) ) ) ;
}
}
private async void LoginWinoAccountClicked ( object sender , RoutedEventArgs e )
{
2026-03-16 15:02:39 +01:00
WinoAccountFlyout . Hide ( ) ;
2026-03-16 01:33:27 +01:00
var account = await MailDialogService . ShowWinoAccountLoginDialogAsync ( ) ;
if ( account ! = null )
{
ShowInfoBarMessage ( new InfoBarMessageRequested (
InfoBarMessageType . Success ,
Translator . GeneralTitle_Info ,
string . Format ( Translator . WinoAccount_LoginSuccessMessage , account . Email ) ) ) ;
}
}
private async void SignOutWinoAccountClicked ( object sender , RoutedEventArgs e )
{
var activeAccount = await WinoAccountProfileService . GetActiveAccountAsync ( ) ;
if ( activeAccount = = null )
{
ShowInfoBarMessage ( new InfoBarMessageRequested (
InfoBarMessageType . Warning ,
Translator . GeneralTitle_Info ,
Translator . WinoAccount_SignOut_NoAccountMessage ) ) ;
return ;
}
await WinoAccountProfileService . SignOutAsync ( ) ;
ShowInfoBarMessage ( new InfoBarMessageRequested (
InfoBarMessageType . Success ,
Translator . GeneralTitle_Info ,
string . Format ( Translator . WinoAccount_SignOut_SuccessMessage , activeAccount . Email ) ) ) ;
2025-10-21 01:27:29 +02:00
}
2025-12-26 20:46:48 +01:00
2025-09-29 11:16:14 +02:00
}