Custom print dialog and better message registrations
This commit is contained in:
@@ -50,4 +50,18 @@ public sealed partial class AppShell : AppShellAbstract,
|
||||
|
||||
private void AppBarBackButtonClicked(Core.UWP.Controls.WinoAppTitleBar sender, RoutedEventArgs args)
|
||||
=> ViewModel.NavigationService.GoBack();
|
||||
|
||||
protected override void RegisterRecipients()
|
||||
{
|
||||
base.RegisterRecipients();
|
||||
|
||||
WeakReferenceMessenger.Default.Register<CalendarDisplayTypeChangedMessage>(this);
|
||||
}
|
||||
|
||||
protected override void UnregisterRecipients()
|
||||
{
|
||||
base.UnregisterRecipients();
|
||||
|
||||
WeakReferenceMessenger.Default.Unregister<CalendarDisplayTypeChangedMessage>(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Threading.Tasks;
|
||||
using Wino.Core.Domain.Enums;
|
||||
using Wino.Core.Domain.Models.Accounts;
|
||||
using Wino.Core.Domain.Models.Common;
|
||||
using Wino.Core.Domain.Models.Printing;
|
||||
|
||||
namespace Wino.Core.Domain.Interfaces;
|
||||
|
||||
@@ -28,4 +29,5 @@ public interface IDialogServiceBase
|
||||
IAccountCreationDialog GetAccountCreationDialog(AccountCreationDialogResult accountCreationDialogResult);
|
||||
Task<List<SharedFile>> PickFilesAsync(params object[] typeFilters);
|
||||
Task<string> PickFilePathAsync(string saveFileName);
|
||||
Task<WebView2PrintSettingsModel> ShowPrintDialogAsync(WebView2PrintSettingsModel initialSettings = null);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace Wino.Core.Domain.Models.MailItem;
|
||||
/// </summary>
|
||||
public class MailDragPackage
|
||||
{
|
||||
public MailDragPackage(IEnumerable<MailCopy> draggingMails)
|
||||
public MailDragPackage(IEnumerable<object> draggingMails)
|
||||
{
|
||||
DraggingMails = draggingMails;
|
||||
}
|
||||
@@ -21,5 +21,5 @@ public class MailDragPackage
|
||||
];
|
||||
}
|
||||
|
||||
public IEnumerable<MailCopy> DraggingMails { get; set; }
|
||||
public IEnumerable<object> DraggingMails { get; set; }
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.ComponentModel;
|
||||
using System;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Wino.Core.Domain.Enums;
|
||||
|
||||
namespace Wino.Core.Domain.Models.Printing;
|
||||
@@ -6,339 +7,131 @@ namespace Wino.Core.Domain.Models.Printing;
|
||||
/// <summary>
|
||||
/// Wrapper model for CoreWebView2PrintSettings that provides bindable properties for UI controls.
|
||||
/// </summary>
|
||||
public class WebView2PrintSettingsModel : INotifyPropertyChanged
|
||||
public partial class WebView2PrintSettingsModel : ObservableObject
|
||||
{
|
||||
private string _printerName = string.Empty;
|
||||
private PrintOrientation _orientation = PrintOrientation.Portrait;
|
||||
private PrintColorMode _colorMode = PrintColorMode.Color;
|
||||
private PrintCollation _collation = PrintCollation.Default;
|
||||
private PrintDuplex _duplex = PrintDuplex.Default;
|
||||
private PrintMediaSize _mediaSize = PrintMediaSize.Default;
|
||||
private int _copies = 1;
|
||||
private double _marginTop = 1.0;
|
||||
private double _marginBottom = 1.0;
|
||||
private double _marginLeft = 1.0;
|
||||
private double _marginRight = 1.0;
|
||||
private bool _shouldPrintBackgrounds = false;
|
||||
private bool _shouldPrintSelectionOnly = false;
|
||||
private bool _shouldPrintHeaderAndFooter = true;
|
||||
private string _headerTitle = string.Empty;
|
||||
private string _footerUri = string.Empty;
|
||||
private double _scaleFactor = 1.0;
|
||||
private int _pagesPerSide = 1;
|
||||
private string _pageRanges = string.Empty;
|
||||
[ObservableProperty]
|
||||
public partial string PrinterName { get; set; } = string.Empty;
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
[ObservableProperty]
|
||||
public partial PrintOrientation Orientation { get; set; } = PrintOrientation.Portrait;
|
||||
|
||||
[ObservableProperty]
|
||||
public partial PrintColorMode ColorMode { get; set; } = PrintColorMode.Color;
|
||||
|
||||
[ObservableProperty]
|
||||
public partial PrintCollation Collation { get; set; } = PrintCollation.Default;
|
||||
|
||||
[ObservableProperty]
|
||||
public partial PrintDuplex Duplex { get; set; } = PrintDuplex.Default;
|
||||
|
||||
[ObservableProperty]
|
||||
public partial PrintMediaSize MediaSize { get; set; } = PrintMediaSize.Default;
|
||||
|
||||
[ObservableProperty]
|
||||
public partial int Copies { get; set; } = 1;
|
||||
|
||||
[ObservableProperty]
|
||||
public partial double MarginTop { get; set; } = 1.0;
|
||||
|
||||
[ObservableProperty]
|
||||
public partial double MarginBottom { get; set; } = 1.0;
|
||||
|
||||
[ObservableProperty]
|
||||
public partial double MarginLeft { get; set; } = 1.0;
|
||||
|
||||
[ObservableProperty]
|
||||
public partial double MarginRight { get; set; } = 1.0;
|
||||
|
||||
[ObservableProperty]
|
||||
public partial bool ShouldPrintBackgrounds { get; set; } = false;
|
||||
|
||||
[ObservableProperty]
|
||||
public partial bool ShouldPrintSelectionOnly { get; set; } = false;
|
||||
|
||||
[ObservableProperty]
|
||||
public partial bool ShouldPrintHeaderAndFooter { get; set; } = true;
|
||||
|
||||
[ObservableProperty]
|
||||
public partial string HeaderTitle { get; set; } = string.Empty;
|
||||
|
||||
[ObservableProperty]
|
||||
public partial string FooterUri { get; set; } = string.Empty;
|
||||
|
||||
[ObservableProperty]
|
||||
public partial double ScaleFactor { get; set; } = 1.0;
|
||||
|
||||
[ObservableProperty]
|
||||
public partial int PagesPerSide { get; set; } = 1;
|
||||
|
||||
[ObservableProperty]
|
||||
public partial string PageRanges { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Name of the printer to use for printing.
|
||||
/// Partial method for validation when Copies property changes.
|
||||
/// </summary>
|
||||
public string PrinterName
|
||||
partial void OnCopiesChanged(int value)
|
||||
{
|
||||
get => _printerName;
|
||||
set
|
||||
if (value <= 0)
|
||||
{
|
||||
if (_printerName != value)
|
||||
{
|
||||
_printerName = value;
|
||||
OnPropertyChanged(nameof(PrinterName));
|
||||
}
|
||||
Copies = 1; // Reset to minimum valid value
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Orientation of the printed document.
|
||||
/// Partial method for validation when ScaleFactor property changes.
|
||||
/// </summary>
|
||||
public PrintOrientation Orientation
|
||||
partial void OnScaleFactorChanged(double value)
|
||||
{
|
||||
get => _orientation;
|
||||
set
|
||||
if (value < 0.1 || value > 2.0)
|
||||
{
|
||||
if (_orientation != value)
|
||||
{
|
||||
_orientation = value;
|
||||
OnPropertyChanged(nameof(Orientation));
|
||||
}
|
||||
ScaleFactor = Math.Clamp(value, 0.1, 2.0);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Color mode for printing.
|
||||
/// Partial method for validation when PagesPerSide property changes.
|
||||
/// </summary>
|
||||
public PrintColorMode ColorMode
|
||||
{
|
||||
get => _colorMode;
|
||||
set
|
||||
{
|
||||
if (_colorMode != value)
|
||||
{
|
||||
_colorMode = value;
|
||||
OnPropertyChanged(nameof(ColorMode));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Collation setting for multiple copies.
|
||||
/// </summary>
|
||||
public PrintCollation Collation
|
||||
{
|
||||
get => _collation;
|
||||
set
|
||||
{
|
||||
if (_collation != value)
|
||||
{
|
||||
_collation = value;
|
||||
OnPropertyChanged(nameof(Collation));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Duplex printing mode.
|
||||
/// </summary>
|
||||
public PrintDuplex Duplex
|
||||
{
|
||||
get => _duplex;
|
||||
set
|
||||
{
|
||||
if (_duplex != value)
|
||||
{
|
||||
_duplex = value;
|
||||
OnPropertyChanged(nameof(Duplex));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Media size for printing.
|
||||
/// </summary>
|
||||
public PrintMediaSize MediaSize
|
||||
{
|
||||
get => _mediaSize;
|
||||
set
|
||||
{
|
||||
if (_mediaSize != value)
|
||||
{
|
||||
_mediaSize = value;
|
||||
OnPropertyChanged(nameof(MediaSize));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Number of copies to print.
|
||||
/// </summary>
|
||||
public int Copies
|
||||
{
|
||||
get => _copies;
|
||||
set
|
||||
{
|
||||
if (_copies != value && value > 0)
|
||||
{
|
||||
_copies = value;
|
||||
OnPropertyChanged(nameof(Copies));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Top margin in inches.
|
||||
/// </summary>
|
||||
public double MarginTop
|
||||
{
|
||||
get => _marginTop;
|
||||
set
|
||||
{
|
||||
if (_marginTop != value && value >= 0)
|
||||
{
|
||||
_marginTop = value;
|
||||
OnPropertyChanged(nameof(MarginTop));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bottom margin in inches.
|
||||
/// </summary>
|
||||
public double MarginBottom
|
||||
{
|
||||
get => _marginBottom;
|
||||
set
|
||||
{
|
||||
if (_marginBottom != value && value >= 0)
|
||||
{
|
||||
_marginBottom = value;
|
||||
OnPropertyChanged(nameof(MarginBottom));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Left margin in inches.
|
||||
/// </summary>
|
||||
public double MarginLeft
|
||||
{
|
||||
get => _marginLeft;
|
||||
set
|
||||
{
|
||||
if (_marginLeft != value && value >= 0)
|
||||
{
|
||||
_marginLeft = value;
|
||||
OnPropertyChanged(nameof(MarginLeft));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Right margin in inches.
|
||||
/// </summary>
|
||||
public double MarginRight
|
||||
{
|
||||
get => _marginRight;
|
||||
set
|
||||
{
|
||||
if (_marginRight != value && value >= 0)
|
||||
{
|
||||
_marginRight = value;
|
||||
OnPropertyChanged(nameof(MarginRight));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether to print background colors and images.
|
||||
/// </summary>
|
||||
public bool ShouldPrintBackgrounds
|
||||
{
|
||||
get => _shouldPrintBackgrounds;
|
||||
set
|
||||
{
|
||||
if (_shouldPrintBackgrounds != value)
|
||||
{
|
||||
_shouldPrintBackgrounds = value;
|
||||
OnPropertyChanged(nameof(ShouldPrintBackgrounds));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether to print only the selected content.
|
||||
/// </summary>
|
||||
public bool ShouldPrintSelectionOnly
|
||||
{
|
||||
get => _shouldPrintSelectionOnly;
|
||||
set
|
||||
{
|
||||
if (_shouldPrintSelectionOnly != value)
|
||||
{
|
||||
_shouldPrintSelectionOnly = value;
|
||||
OnPropertyChanged(nameof(ShouldPrintSelectionOnly));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether to print header and footer.
|
||||
/// </summary>
|
||||
public bool ShouldPrintHeaderAndFooter
|
||||
{
|
||||
get => _shouldPrintHeaderAndFooter;
|
||||
set
|
||||
{
|
||||
if (_shouldPrintHeaderAndFooter != value)
|
||||
{
|
||||
_shouldPrintHeaderAndFooter = value;
|
||||
OnPropertyChanged(nameof(ShouldPrintHeaderAndFooter));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Title to display in the header.
|
||||
/// </summary>
|
||||
public string HeaderTitle
|
||||
{
|
||||
get => _headerTitle;
|
||||
set
|
||||
{
|
||||
if (_headerTitle != value)
|
||||
{
|
||||
_headerTitle = value ?? string.Empty;
|
||||
OnPropertyChanged(nameof(HeaderTitle));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// URI to display in the footer.
|
||||
/// </summary>
|
||||
public string FooterUri
|
||||
{
|
||||
get => _footerUri;
|
||||
set
|
||||
{
|
||||
if (_footerUri != value)
|
||||
{
|
||||
_footerUri = value ?? string.Empty;
|
||||
OnPropertyChanged(nameof(FooterUri));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scale factor for printing (0.1 to 2.0).
|
||||
/// </summary>
|
||||
public double ScaleFactor
|
||||
{
|
||||
get => _scaleFactor;
|
||||
set
|
||||
{
|
||||
if (_scaleFactor != value && value >= 0.1 && value <= 2.0)
|
||||
{
|
||||
_scaleFactor = value;
|
||||
OnPropertyChanged(nameof(ScaleFactor));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Number of pages to print per sheet (1, 2, 4, 6, 9, 16).
|
||||
/// </summary>
|
||||
public int PagesPerSide
|
||||
{
|
||||
get => _pagesPerSide;
|
||||
set
|
||||
partial void OnPagesPerSideChanged(int value)
|
||||
{
|
||||
var validValues = new[] { 1, 2, 4, 6, 9, 16 };
|
||||
if (_pagesPerSide != value && System.Array.IndexOf(validValues, value) >= 0)
|
||||
if (System.Array.IndexOf(validValues, value) < 0)
|
||||
{
|
||||
_pagesPerSide = value;
|
||||
OnPropertyChanged(nameof(PagesPerSide));
|
||||
}
|
||||
PagesPerSide = 1; // Reset to default valid value
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Page ranges to print (e.g., "1-3,5,7-9").
|
||||
/// Partial method for validation when margin properties change.
|
||||
/// </summary>
|
||||
public string PageRanges
|
||||
partial void OnMarginTopChanged(double value)
|
||||
{
|
||||
get => _pageRanges;
|
||||
set
|
||||
if (value < 0)
|
||||
{
|
||||
if (_pageRanges != value)
|
||||
{
|
||||
_pageRanges = value ?? string.Empty;
|
||||
OnPropertyChanged(nameof(PageRanges));
|
||||
}
|
||||
MarginTop = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected virtual void OnPropertyChanged(string propertyName)
|
||||
partial void OnMarginBottomChanged(double value)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
if (value < 0)
|
||||
{
|
||||
MarginBottom = 0;
|
||||
}
|
||||
}
|
||||
|
||||
partial void OnMarginLeftChanged(double value)
|
||||
{
|
||||
if (value < 0)
|
||||
{
|
||||
MarginLeft = 0;
|
||||
}
|
||||
}
|
||||
|
||||
partial void OnMarginRightChanged(double value)
|
||||
{
|
||||
if (value < 0)
|
||||
{
|
||||
MarginRight = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,4 +9,18 @@ public class CalendarBaseViewModel : CoreBaseViewModel, IRecipient<CalendarItemA
|
||||
public void Receive(CalendarItemAdded message) => OnCalendarItemAdded(message.CalendarItem);
|
||||
|
||||
protected virtual void OnCalendarItemAdded(CalendarItem calendarItem) { }
|
||||
|
||||
protected override void RegisterRecipients()
|
||||
{
|
||||
base.RegisterRecipients();
|
||||
|
||||
Messenger.Register<CalendarItemAdded>(this);
|
||||
}
|
||||
|
||||
protected override void UnregisterRecipients()
|
||||
{
|
||||
base.UnregisterRecipients();
|
||||
|
||||
Messenger.Unregister<CalendarItemAdded>(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,9 +33,15 @@ public class CoreBaseViewModel : ObservableRecipient,
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void OnNavigatedTo(NavigationMode mode, object parameters) { IsActive = true; }
|
||||
public virtual void OnNavigatedTo(NavigationMode mode, object parameters)
|
||||
{
|
||||
RegisterRecipients();
|
||||
}
|
||||
|
||||
public virtual void OnNavigatedFrom(NavigationMode mode, object parameters) { IsActive = false; }
|
||||
public virtual void OnNavigatedFrom(NavigationMode mode, object parameters)
|
||||
{
|
||||
UnregisterRecipients();
|
||||
}
|
||||
|
||||
public virtual void OnPageLoaded() { }
|
||||
|
||||
@@ -44,6 +50,16 @@ public class CoreBaseViewModel : ObservableRecipient,
|
||||
|
||||
protected virtual void OnDispatcherAssigned() { }
|
||||
|
||||
/// <summary>
|
||||
/// Register message recipients for this view model. Override to register specific message types.
|
||||
/// </summary>
|
||||
protected virtual void RegisterRecipients() { }
|
||||
|
||||
/// <summary>
|
||||
/// Unregister message recipients for this view model. Override to unregister specific message types.
|
||||
/// </summary>
|
||||
protected virtual void UnregisterRecipients() { }
|
||||
|
||||
protected virtual void OnAccountCreated(MailAccount createdAccount) { }
|
||||
protected virtual void OnAccountRemoved(MailAccount removedAccount) { }
|
||||
protected virtual void OnAccountUpdated(MailAccount updatedAccount) { }
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.UI.Xaml;
|
||||
@@ -27,6 +26,16 @@ public partial class BasePage : Page, IRecipient<LanguageChanged>
|
||||
}
|
||||
|
||||
public virtual void OnLanguageChanged() { }
|
||||
|
||||
/// <summary>
|
||||
/// Register message recipients for this page. Override to register specific message types.
|
||||
/// </summary>
|
||||
protected virtual void RegisterRecipients() { }
|
||||
|
||||
/// <summary>
|
||||
/// Unregister message recipients for this page. Override to unregister specific message types.
|
||||
/// </summary>
|
||||
protected virtual void UnregisterRecipients() { }
|
||||
}
|
||||
|
||||
public abstract class BasePage<T> : BasePage where T : CoreBaseViewModel
|
||||
@@ -49,10 +58,7 @@ public abstract class BasePage<T> : BasePage where T : CoreBaseViewModel
|
||||
|
||||
private void PageLoaded(object sender, RoutedEventArgs e) => ViewModel.OnPageLoaded();
|
||||
|
||||
~BasePage()
|
||||
{
|
||||
Debug.WriteLine($"Disposed {GetType().Name}");
|
||||
}
|
||||
~BasePage() { Debug.WriteLine($"Disposed {GetType().Name}"); }
|
||||
|
||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
@@ -61,8 +67,8 @@ public abstract class BasePage<T> : BasePage where T : CoreBaseViewModel
|
||||
var mode = GetNavigationMode(e.NavigationMode);
|
||||
var parameter = e.Parameter;
|
||||
|
||||
WeakReferenceMessenger.Default.UnregisterAll(this);
|
||||
WeakReferenceMessenger.Default.Register<LanguageChanged>(this);
|
||||
RegisterRecipients();
|
||||
|
||||
ViewModel.OnNavigatedTo(mode, parameter);
|
||||
}
|
||||
@@ -74,7 +80,8 @@ public abstract class BasePage<T> : BasePage where T : CoreBaseViewModel
|
||||
var mode = GetNavigationMode(e.NavigationMode);
|
||||
var parameter = e.Parameter;
|
||||
|
||||
WeakReferenceMessenger.Default.UnregisterAll(this);
|
||||
WeakReferenceMessenger.Default.Unregister<LanguageChanged>(this);
|
||||
UnregisterRecipients();
|
||||
|
||||
ViewModel.OnNavigatedFrom(mode, parameter);
|
||||
|
||||
|
||||
@@ -1,220 +1,54 @@
|
||||
<ContentDialog x:Class="Wino.Core.WinUI.Dialogs.PrintDialog"
|
||||
<ContentDialog
|
||||
x:Class="Wino.Core.WinUI.Dialogs.PrintDialog"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d"
|
||||
xmlns:printing="using:Wino.Core.Domain.Models.Printing"
|
||||
Title="Print Settings"
|
||||
PrimaryButtonText="Print"
|
||||
SecondaryButtonText="Cancel"
|
||||
MinWidth="400"
|
||||
MinHeight="300"
|
||||
DefaultButton="Primary"
|
||||
MinWidth="600"
|
||||
MinHeight="500"
|
||||
Loaded="PrintDialog_Loaded"
|
||||
PrimaryButtonClick="ContentDialog_PrimaryButtonClick"
|
||||
SecondaryButtonClick="ContentDialog_SecondaryButtonClick">
|
||||
PrimaryButtonText="Print"
|
||||
SecondaryButtonClick="ContentDialog_SecondaryButtonClick"
|
||||
SecondaryButtonText="Cancel"
|
||||
Style="{StaticResource WinoDialogStyle}"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<ScrollViewer>
|
||||
<StackPanel Spacing="16" Margin="20">
|
||||
<StackPanel Margin="20" Spacing="16">
|
||||
|
||||
<!-- Printer Selection -->
|
||||
<StackPanel Spacing="8">
|
||||
<TextBlock Text="Printer" FontWeight="SemiBold" />
|
||||
<ComboBox x:Name="PrinterComboBox"
|
||||
ItemsSource="{x:Bind ViewModel.AvailablePrinters, Mode=OneWay}"
|
||||
SelectedItem="{x:Bind ViewModel.PrintSettings.PrinterName, Mode=TwoWay}"
|
||||
Header="Select Printer"
|
||||
HorizontalAlignment="Stretch" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- Print Options Grid -->
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="20" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- Left Column -->
|
||||
<StackPanel Grid.Column="0" Spacing="16">
|
||||
<ComboBox
|
||||
x:Name="PrinterComboBox"
|
||||
HorizontalAlignment="Stretch"
|
||||
Header="Printer"
|
||||
SelectedItem="{x:Bind PrintSettings.PrinterName, Mode=TwoWay}"
|
||||
SelectionChanged="PrinterComboBox_SelectionChanged" />
|
||||
|
||||
<!-- Copies -->
|
||||
<StackPanel Spacing="8">
|
||||
<TextBlock Text="Copies" FontWeight="SemiBold" />
|
||||
<NumberBox Value="{x:Bind ViewModel.PrintSettings.Copies, Mode=TwoWay}"
|
||||
Minimum="1" Maximum="999"
|
||||
SpinButtonPlacementMode="Inline" />
|
||||
</StackPanel>
|
||||
<NumberBox
|
||||
Header="Copies"
|
||||
Maximum="999"
|
||||
Minimum="1"
|
||||
SpinButtonPlacementMode="Inline"
|
||||
Value="{x:Bind PrintSettings.Copies, Mode=TwoWay}" />
|
||||
|
||||
<!-- Orientation -->
|
||||
<StackPanel Spacing="8">
|
||||
<TextBlock Text="Orientation" FontWeight="SemiBold" />
|
||||
<RadioButtons SelectedIndex="{x:Bind ViewModel.OrientationIndex, Mode=TwoWay}">
|
||||
<RadioButtons
|
||||
x:Name="OrientationRadioButtons"
|
||||
Header="Orientation"
|
||||
SelectionChanged="OrientationRadio_SelectionChanged">
|
||||
<RadioButton Content="Portrait" />
|
||||
<RadioButton Content="Landscape" />
|
||||
</RadioButtons>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Color Mode -->
|
||||
<StackPanel Spacing="8">
|
||||
<TextBlock Text="Color" FontWeight="SemiBold" />
|
||||
<RadioButtons SelectedIndex="{x:Bind ViewModel.ColorModeIndex, Mode=TwoWay}">
|
||||
<RadioButton Content="Default" />
|
||||
<RadioButton Content="Color" />
|
||||
<RadioButton Content="Grayscale" />
|
||||
</RadioButtons>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Media Size -->
|
||||
<StackPanel Spacing="8">
|
||||
<TextBlock Text="Paper Size" FontWeight="SemiBold" />
|
||||
<ComboBox SelectedIndex="{x:Bind ViewModel.MediaSizeIndex, Mode=TwoWay}"
|
||||
HorizontalAlignment="Stretch">
|
||||
<ComboBoxItem Content="Default" />
|
||||
<ComboBoxItem Content="Letter (8.5 x 11 in)" />
|
||||
<ComboBoxItem Content="Legal (8.5 x 14 in)" />
|
||||
<ComboBoxItem Content="A4 (210 x 297 mm)" />
|
||||
<ComboBoxItem Content="A3 (297 x 420 mm)" />
|
||||
<ComboBoxItem Content="A5 (148 x 210 mm)" />
|
||||
<ComboBoxItem Content="Tabloid (11 x 17 in)" />
|
||||
<ComboBoxItem Content="Executive (7.25 x 10.5 in)" />
|
||||
<ComboBoxItem Content="B4 (250 x 353 mm)" />
|
||||
<ComboBoxItem Content="B5 (176 x 250 mm)" />
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
|
||||
</StackPanel>
|
||||
|
||||
<!-- Right Column -->
|
||||
<StackPanel Grid.Column="2" Spacing="16">
|
||||
|
||||
<!-- Duplex -->
|
||||
<StackPanel Spacing="8">
|
||||
<TextBlock Text="Duplex" FontWeight="SemiBold" />
|
||||
<RadioButtons SelectedIndex="{x:Bind ViewModel.DuplexIndex, Mode=TwoWay}">
|
||||
<RadioButton Content="Default" />
|
||||
<RadioButton Content="Single-sided" />
|
||||
<RadioButton Content="Double-sided (Short Edge)" />
|
||||
<RadioButton Content="Double-sided (Long Edge)" />
|
||||
</RadioButtons>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Collation -->
|
||||
<StackPanel Spacing="8">
|
||||
<TextBlock Text="Collation" FontWeight="SemiBold" />
|
||||
<RadioButtons SelectedIndex="{x:Bind ViewModel.CollationIndex, Mode=TwoWay}">
|
||||
<RadioButton Content="Default" />
|
||||
<RadioButton Content="Collated" />
|
||||
<RadioButton Content="Uncollated" />
|
||||
</RadioButtons>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Pages Per Side -->
|
||||
<StackPanel Spacing="8">
|
||||
<TextBlock Text="Pages Per Side" FontWeight="SemiBold" />
|
||||
<ComboBox SelectedIndex="{x:Bind ViewModel.PagesPerSideIndex, Mode=TwoWay}"
|
||||
HorizontalAlignment="Stretch">
|
||||
<ComboBoxItem Content="1" />
|
||||
<ComboBoxItem Content="2" />
|
||||
<ComboBoxItem Content="4" />
|
||||
<ComboBoxItem Content="6" />
|
||||
<ComboBoxItem Content="9" />
|
||||
<ComboBoxItem Content="16" />
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<!-- Page Range -->
|
||||
<StackPanel Spacing="8">
|
||||
<TextBlock Text="Page Range" FontWeight="SemiBold" />
|
||||
<RadioButtons SelectedIndex="{x:Bind ViewModel.PageRangeOptionIndex, Mode=TwoWay}">
|
||||
<RadioButton Content="All pages" />
|
||||
<RadioButton Content="Custom range" />
|
||||
</RadioButtons>
|
||||
<TextBox x:Name="PageRangeTextBox"
|
||||
Text="{x:Bind ViewModel.PrintSettings.PageRanges, Mode=TwoWay}"
|
||||
PlaceholderText="e.g., 1-3,5,7-9"
|
||||
IsEnabled="{x:Bind ViewModel.IsCustomPageRange, Mode=OneWay}"
|
||||
Margin="0,8,0,0" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- Scale Factor -->
|
||||
<StackPanel Spacing="8">
|
||||
<TextBlock Text="Scale" FontWeight="SemiBold" />
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="80" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Slider x:Name="ScaleSlider"
|
||||
Value="{x:Bind ViewModel.PrintSettings.ScaleFactor, Mode=TwoWay}"
|
||||
Minimum="0.1" Maximum="2.0" StepFrequency="0.1"
|
||||
Grid.Column="0" />
|
||||
<TextBlock Text="{x:Bind ViewModel.ScalePercentageText, Mode=OneWay}"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Grid.Column="1" />
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Margins -->
|
||||
<StackPanel Spacing="8">
|
||||
<TextBlock Text="Margins (inches)" FontWeight="SemiBold" />
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock Text="Top" Grid.Column="0" Grid.Row="0" HorizontalAlignment="Center" />
|
||||
<TextBlock Text="Bottom" Grid.Column="1" Grid.Row="0" HorizontalAlignment="Center" />
|
||||
<TextBlock Text="Left" Grid.Column="2" Grid.Row="0" HorizontalAlignment="Center" />
|
||||
<TextBlock Text="Right" Grid.Column="3" Grid.Row="0" HorizontalAlignment="Center" />
|
||||
|
||||
<NumberBox Value="{x:Bind ViewModel.PrintSettings.MarginTop, Mode=TwoWay}"
|
||||
Minimum="0" Maximum="10" StepFrequency="0.1"
|
||||
Grid.Column="0" Grid.Row="1" Margin="4" />
|
||||
<NumberBox Value="{x:Bind ViewModel.PrintSettings.MarginBottom, Mode=TwoWay}"
|
||||
Minimum="0" Maximum="10" StepFrequency="0.1"
|
||||
Grid.Column="1" Grid.Row="1" Margin="4" />
|
||||
<NumberBox Value="{x:Bind ViewModel.PrintSettings.MarginLeft, Mode=TwoWay}"
|
||||
Minimum="0" Maximum="10" StepFrequency="0.1"
|
||||
Grid.Column="2" Grid.Row="1" Margin="4" />
|
||||
<NumberBox Value="{x:Bind ViewModel.PrintSettings.MarginRight, Mode=TwoWay}"
|
||||
Minimum="0" Maximum="10" StepFrequency="0.1"
|
||||
Grid.Column="3" Grid.Row="1" Margin="4" />
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Print Options -->
|
||||
<StackPanel Spacing="8">
|
||||
<TextBlock Text="Options" FontWeight="SemiBold" />
|
||||
<CheckBox Content="Print backgrounds"
|
||||
IsChecked="{x:Bind ViewModel.PrintSettings.ShouldPrintBackgrounds, Mode=TwoWay}" />
|
||||
<CheckBox Content="Print selection only"
|
||||
IsChecked="{x:Bind ViewModel.PrintSettings.ShouldPrintSelectionOnly, Mode=TwoWay}" />
|
||||
<CheckBox Content="Print headers and footers"
|
||||
IsChecked="{x:Bind ViewModel.PrintSettings.ShouldPrintHeaderAndFooter, Mode=TwoWay}" />
|
||||
<TextBlock Text="Options" />
|
||||
<CheckBox Content="Print backgrounds" IsChecked="{x:Bind PrintSettings.ShouldPrintBackgrounds, Mode=TwoWay}" />
|
||||
<CheckBox Content="Print headers and footers" IsChecked="{x:Bind PrintSettings.ShouldPrintHeaderAndFooter, Mode=TwoWay}" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- Header and Footer -->
|
||||
<StackPanel Spacing="8" Visibility="{x:Bind ViewModel.PrintSettings.ShouldPrintHeaderAndFooter, Mode=OneWay}">
|
||||
<TextBlock Text="Header & Footer" FontWeight="SemiBold" />
|
||||
<TextBox Header="Header Title"
|
||||
Text="{x:Bind ViewModel.PrintSettings.HeaderTitle, Mode=TwoWay}"
|
||||
PlaceholderText="Document title" />
|
||||
<TextBox Header="Footer URI"
|
||||
Text="{x:Bind ViewModel.PrintSettings.FooterUri, Mode=TwoWay}"
|
||||
PlaceholderText="Document URL" />
|
||||
</StackPanel>
|
||||
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</ContentDialog>
|
||||
@@ -1,7 +1,11 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing.Printing;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Serilog;
|
||||
using Wino.Core.Domain.Enums;
|
||||
using Wino.Core.Domain.Models.Printing;
|
||||
using Wino.Core.WinUI.Models;
|
||||
|
||||
namespace Wino.Core.WinUI.Dialogs;
|
||||
|
||||
@@ -10,32 +14,40 @@ namespace Wino.Core.WinUI.Dialogs;
|
||||
/// </summary>
|
||||
public sealed partial class PrintDialog : ContentDialog
|
||||
{
|
||||
/// <summary>
|
||||
/// The ViewModel that handles the dialog's data binding and logic.
|
||||
/// </summary>
|
||||
public PrintDialogViewModel ViewModel { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the configured print settings from the dialog.
|
||||
/// </summary>
|
||||
public WebView2PrintSettingsModel PrintSettings => ViewModel.PrintSettings;
|
||||
public WebView2PrintSettingsModel PrintSettings { get; set; } = new WebView2PrintSettingsModel();
|
||||
|
||||
public PrintDialog()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
ViewModel = new PrintDialogViewModel();
|
||||
ViewModel.Initialize();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the dialog with existing print settings.
|
||||
/// </summary>
|
||||
/// <param name="printSettings">The initial print settings to load.</param>
|
||||
public PrintDialog(WebView2PrintSettingsModel printSettings)
|
||||
public PrintDialog(WebView2PrintSettingsModel printSettings = null)
|
||||
{
|
||||
if (printSettings != null) PrintSettings = printSettings;
|
||||
|
||||
this.InitializeComponent();
|
||||
ViewModel = new PrintDialogViewModel();
|
||||
ViewModel.Initialize(printSettings);
|
||||
}
|
||||
|
||||
private void PrintDialog_Loaded(object sender, Microsoft.UI.Xaml.RoutedEventArgs e) => LoadSettingsToUI(PrintSettings);
|
||||
|
||||
private void OrientationRadio_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (sender is RadioButtons radioButtons)
|
||||
{
|
||||
PrintSettings.Orientation = (PrintOrientation)radioButtons.SelectedIndex;
|
||||
}
|
||||
}
|
||||
|
||||
private void PrinterComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (sender is ComboBox comboBox && comboBox.SelectedItem != null)
|
||||
{
|
||||
PrintSettings.PrinterName = comboBox.SelectedItem.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -44,7 +56,85 @@ public sealed partial class PrintDialog : ContentDialog
|
||||
/// <param name="printers">List of available printer names.</param>
|
||||
public void SetAvailablePrinters(IEnumerable<string> printers)
|
||||
{
|
||||
ViewModel.SetAvailablePrinters(printers);
|
||||
var printerList = printers?.ToList() ?? new List<string>();
|
||||
|
||||
if (this.FindName("PrinterComboBox") is ComboBox printerComboBox)
|
||||
{
|
||||
printerComboBox.ItemsSource = printerList;
|
||||
|
||||
if (printerList.Any())
|
||||
{
|
||||
// Set to first printer or to the one in settings
|
||||
var targetPrinter = !string.IsNullOrEmpty(PrintSettings.PrinterName)
|
||||
? PrintSettings.PrinterName
|
||||
: printerList.First();
|
||||
|
||||
var index = printerList.IndexOf(targetPrinter);
|
||||
printerComboBox.SelectedIndex = index >= 0 ? index : 0;
|
||||
|
||||
// Update the settings model with the selected printer
|
||||
PrintSettings.PrinterName = printerComboBox.SelectedItem?.ToString() ?? string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads available printers asynchronously and sets them in the dialog.
|
||||
/// </summary>
|
||||
public async Task LoadAvailablePrintersAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
var printers = await Task.Run(() =>
|
||||
{
|
||||
var printerList = new List<string>();
|
||||
|
||||
// Get all installed printers using System.Drawing.Printing
|
||||
foreach (string printerName in PrinterSettings.InstalledPrinters)
|
||||
{
|
||||
printerList.Add(printerName);
|
||||
}
|
||||
|
||||
return printerList.AsEnumerable();
|
||||
});
|
||||
|
||||
SetAvailablePrinters(printers);
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
// Log the exception if logging is available
|
||||
Log.Error(ex, "Error getting available printers");
|
||||
|
||||
// Set empty list if printer discovery fails
|
||||
SetAvailablePrinters(Enumerable.Empty<string>());
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadSettingsToUI(WebView2PrintSettingsModel settings)
|
||||
{
|
||||
if (settings == null) return;
|
||||
|
||||
// Only handle orientation manually since other properties are bound via x:Bind
|
||||
if (this.FindName("OrientationRadioButtons") is RadioButtons orientationRadio)
|
||||
{
|
||||
orientationRadio.SelectedIndex = (int)settings.Orientation;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateSettingsFromUI()
|
||||
{
|
||||
// Most properties are bound via x:Bind, only handle orientation manually
|
||||
if (this.FindName("OrientationRadioButtons") is RadioButtons orientationRadio)
|
||||
{
|
||||
PrintSettings.Orientation = (PrintOrientation)orientationRadio.SelectedIndex;
|
||||
}
|
||||
|
||||
// Also update printer name from ComboBox since it uses ItemsSource binding
|
||||
if (this.FindName("PrinterComboBox") is ComboBox printerComboBox &&
|
||||
printerComboBox.SelectedItem != null)
|
||||
{
|
||||
PrintSettings.PrinterName = printerComboBox.SelectedItem.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -53,54 +143,31 @@ public sealed partial class PrintDialog : ContentDialog
|
||||
/// <returns>True if settings are valid, false otherwise.</returns>
|
||||
private bool ValidateSettings()
|
||||
{
|
||||
// Validate printer selection
|
||||
if (string.IsNullOrWhiteSpace(PrintSettings.PrinterName))
|
||||
// Check if a printer is selected
|
||||
if (this.FindName("PrinterComboBox") is ComboBox printerComboBox &&
|
||||
printerComboBox.SelectedItem == null)
|
||||
{
|
||||
// Show error message or set focus to printer selection
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate copies
|
||||
// Copies validation is handled by the bound property with validation in the model
|
||||
if (PrintSettings.Copies <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate page ranges if custom range is specified
|
||||
if (ViewModel.IsCustomPageRange && !string.IsNullOrWhiteSpace(PrintSettings.PageRanges))
|
||||
{
|
||||
// Basic validation for page ranges format
|
||||
// More comprehensive validation could be added here
|
||||
var pageRanges = PrintSettings.PageRanges.Trim();
|
||||
if (string.IsNullOrEmpty(pageRanges))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Validate margins
|
||||
if (PrintSettings.MarginTop < 0 || PrintSettings.MarginBottom < 0 ||
|
||||
PrintSettings.MarginLeft < 0 || PrintSettings.MarginRight < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate scale factor
|
||||
if (PrintSettings.ScaleFactor < 0.1 || PrintSettings.ScaleFactor > 2.0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void ContentDialog_PrimaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args)
|
||||
{
|
||||
// Update settings from UI before validation
|
||||
UpdateSettingsFromUI();
|
||||
|
||||
// Validate settings before closing
|
||||
if (!ValidateSettings())
|
||||
{
|
||||
args.Cancel = true;
|
||||
// Could show error message here
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ public static class XamlHelpers
|
||||
public static Visibility ReverseBoolToVisibilityConverter(bool value) => value ? Visibility.Collapsed : Visibility.Visible;
|
||||
public static Visibility ReverseVisibilityConverter(Visibility visibility) => visibility == Visibility.Visible ? Visibility.Collapsed : Visibility.Visible;
|
||||
public static bool ReverseBoolConverter(bool value) => !value;
|
||||
public static bool ShouldDisplayPreview(string text) => text.Any(x => char.IsLetter(x));
|
||||
public static bool ShouldDisplayPreview(string text) => text == null ? false : text.Any(x => char.IsLetter(x));
|
||||
public static bool CountToBooleanConverter(int value) => value > 0;
|
||||
public static bool ObjectEquals(object obj1, object obj2) => object.Equals(obj1, obj2);
|
||||
public static Visibility CountToVisibilityConverter(int value) => value > 0 ? Visibility.Visible : Visibility.Collapsed;
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Wino.Core.Domain.Models.Printing;
|
||||
|
||||
namespace Wino.Core.WinUI.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
/// Service interface for displaying the custom print dialog and managing print settings.
|
||||
/// </summary>
|
||||
public interface IPrintDialogService
|
||||
{
|
||||
/// <summary>
|
||||
/// Shows the print dialog and returns the configured print settings.
|
||||
/// </summary>
|
||||
/// <param name="initialSettings">Initial print settings to populate the dialog with. If null, default settings will be used.</param>
|
||||
/// <param name="availablePrinters">List of available printers to show in the dialog. If null or empty, the service should attempt to discover printers.</param>
|
||||
/// <returns>
|
||||
/// A task that resolves to the configured WebView2PrintSettingsModel if the user clicked Print,
|
||||
/// or null if the user cancelled the dialog.
|
||||
/// </returns>
|
||||
Task<WebView2PrintSettingsModel> ShowPrintDialogAsync(
|
||||
WebView2PrintSettingsModel initialSettings = null,
|
||||
IEnumerable<string> availablePrinters = null);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of available printers on the system.
|
||||
/// </summary>
|
||||
/// <returns>A task that resolves to a list of available printer names.</returns>
|
||||
Task<IEnumerable<string>> GetAvailablePrintersAsync();
|
||||
}
|
||||
@@ -14,6 +14,7 @@ using Wino.Core.Domain.Enums;
|
||||
using Wino.Core.Domain.Interfaces;
|
||||
using Wino.Core.Domain.Models.Accounts;
|
||||
using Wino.Core.Domain.Models.Common;
|
||||
using Wino.Core.Domain.Models.Printing;
|
||||
using Wino.Core.WinUI.Dialogs;
|
||||
using Wino.Core.WinUI.Extensions;
|
||||
using Wino.Dialogs;
|
||||
@@ -294,4 +295,38 @@ public class DialogServiceBase : IDialogServiceBase
|
||||
|
||||
return dialog.Result;
|
||||
}
|
||||
|
||||
public async Task<WebView2PrintSettingsModel> ShowPrintDialogAsync(WebView2PrintSettingsModel initialSettings = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Create the print dialog
|
||||
var dialog = initialSettings != null
|
||||
? new PrintDialog(initialSettings)
|
||||
: new PrintDialog();
|
||||
|
||||
// Set the XamlRoot for proper display
|
||||
dialog.XamlRoot = GetXamlRoot();
|
||||
|
||||
// Get available printers asynchronously when the dialog is loaded
|
||||
dialog.Loaded += async (sender, e) =>
|
||||
{
|
||||
await dialog.LoadAvailablePrintersAsync();
|
||||
};
|
||||
|
||||
// Show the dialog
|
||||
var result = await HandleDialogPresentationAsync(dialog);
|
||||
|
||||
// Return the settings if user clicked Print, otherwise null
|
||||
return result == ContentDialogResult.Primary
|
||||
? dialog.PrintSettings
|
||||
: null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Log the exception if logging is available
|
||||
Log.Error(ex, "Error showing print dialog");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,93 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Drawing.Printing;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Wino.Core.Domain.Models.Printing;
|
||||
using Wino.Core.WinUI.Dialogs;
|
||||
using Wino.Core.WinUI.Interfaces;
|
||||
|
||||
namespace Wino.Core.WinUI.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Service implementation for displaying the custom print dialog and managing print settings.
|
||||
/// </summary>
|
||||
public class PrintDialogService : IPrintDialogService
|
||||
{
|
||||
/// <summary>
|
||||
/// Shows the print dialog and returns the configured print settings.
|
||||
/// </summary>
|
||||
/// <param name="initialSettings">Initial print settings to populate the dialog with. If null, default settings will be used.</param>
|
||||
/// <param name="availablePrinters">List of available printers to show in the dialog. If null or empty, the service will discover printers.</param>
|
||||
/// <returns>
|
||||
/// A task that resolves to the configured WebView2PrintSettingsModel if the user clicked Print,
|
||||
/// or null if the user cancelled the dialog.
|
||||
/// </returns>
|
||||
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern",
|
||||
Justification = "GetProperty is used for backward compatibility and gracefully handles failures")]
|
||||
public async Task<WebView2PrintSettingsModel> ShowPrintDialogAsync(
|
||||
WebView2PrintSettingsModel initialSettings = null,
|
||||
IEnumerable<string> availablePrinters = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Note: XamlRoot will be set by the calling code when showing the dialog
|
||||
|
||||
// Create the print dialog
|
||||
var dialog = initialSettings != null
|
||||
? new PrintDialog(initialSettings)
|
||||
: new PrintDialog();
|
||||
|
||||
// The XamlRoot will be set by the calling code when showing the dialog
|
||||
|
||||
// Get available printers if not provided
|
||||
var printers = availablePrinters ?? await GetAvailablePrintersAsync();
|
||||
dialog.SetAvailablePrinters(printers);
|
||||
|
||||
// Show the dialog
|
||||
var result = await dialog.ShowAsync();
|
||||
|
||||
// Return the settings if user clicked Print, otherwise null
|
||||
return result == Microsoft.UI.Xaml.Controls.ContentDialogResult.Primary
|
||||
? dialog.PrintSettings
|
||||
: null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Log the exception if logging is available
|
||||
System.Diagnostics.Debug.WriteLine($"Error showing print dialog: {ex.Message}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of available printers on the system.
|
||||
/// </summary>
|
||||
/// <returns>A task that resolves to a list of available printer names.</returns>
|
||||
public async Task<IEnumerable<string>> GetAvailablePrintersAsync()
|
||||
{
|
||||
return await Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var printers = new List<string>();
|
||||
|
||||
// Get all installed printers using System.Drawing.Printing
|
||||
foreach (string printerName in PrinterSettings.InstalledPrinters)
|
||||
{
|
||||
printers.Add(printerName);
|
||||
}
|
||||
|
||||
return printers.AsEnumerable();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Log the exception if logging is available
|
||||
System.Diagnostics.Debug.WriteLine($"Error getting available printers: {ex.Message}");
|
||||
return Enumerable.Empty<string>();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
using Microsoft.UI.Xaml;
|
||||
using Wino.Core.WinUI;
|
||||
using Wino.Core.ViewModels;
|
||||
using Wino.Core.WinUI;
|
||||
|
||||
namespace Wino.Views.Abstract;
|
||||
|
||||
|
||||
@@ -26,9 +26,6 @@ public sealed partial class SettingsPage : SettingsPageAbstract, IRecipient<Brea
|
||||
{
|
||||
base.OnNavigatedTo(e);
|
||||
|
||||
// Re-register the breadcrumb navigation handler after base.OnNavigatedTo unregisters all handlers
|
||||
WeakReferenceMessenger.Default.Register<BreadcrumbNavigationRequested>(this);
|
||||
|
||||
SettingsFrame.Navigate(typeof(SettingOptionsPage), null, new SuppressNavigationTransitionInfo());
|
||||
|
||||
var initialRequest = new BreadcrumbNavigationRequested(Translator.MenuSettings, WinoPage.SettingOptionsPage);
|
||||
@@ -63,12 +60,23 @@ public sealed partial class SettingsPage : SettingsPageAbstract, IRecipient<Brea
|
||||
|
||||
protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
|
||||
{
|
||||
// Explicitly unregister our message handlers before base.OnNavigatingFrom calls UnregisterAll
|
||||
WeakReferenceMessenger.Default.Unregister<BreadcrumbNavigationRequested>(this);
|
||||
|
||||
base.OnNavigatingFrom(e);
|
||||
}
|
||||
|
||||
protected override void RegisterRecipients()
|
||||
{
|
||||
base.RegisterRecipients();
|
||||
|
||||
WeakReferenceMessenger.Default.Register<BreadcrumbNavigationRequested>(this);
|
||||
}
|
||||
|
||||
protected override void UnregisterRecipients()
|
||||
{
|
||||
base.UnregisterRecipients();
|
||||
|
||||
WeakReferenceMessenger.Default.Unregister<BreadcrumbNavigationRequested>(this);
|
||||
}
|
||||
|
||||
void IRecipient<BreadcrumbNavigationRequested>.Receive(BreadcrumbNavigationRequested message)
|
||||
{
|
||||
var pageType = ViewModel.NavigationService.GetPageType(message.PageType);
|
||||
|
||||
@@ -1037,4 +1037,36 @@ public partial class AppShellViewModel : MailBaseViewModel,
|
||||
{
|
||||
await MenuItemInvokedOrSelectedAsync(SettingsItem, WinoPage.AppPreferencesPage);
|
||||
}
|
||||
|
||||
protected override void RegisterRecipients()
|
||||
{
|
||||
base.RegisterRecipients();
|
||||
|
||||
Messenger.Register<NavigateManageAccountsRequested>(this);
|
||||
Messenger.Register<MailtoProtocolMessageRequested>(this);
|
||||
Messenger.Register<RefreshUnreadCountsMessage>(this);
|
||||
Messenger.Register<AccountsMenuRefreshRequested>(this);
|
||||
Messenger.Register<MergedInboxRenamed>(this);
|
||||
Messenger.Register<LanguageChanged>(this);
|
||||
Messenger.Register<AccountMenuItemsReordered>(this);
|
||||
Messenger.Register<AccountSynchronizationProgressUpdatedMessage>(this);
|
||||
Messenger.Register<NavigateAppPreferencesRequested>(this);
|
||||
Messenger.Register<AccountFolderConfigurationUpdated>(this);
|
||||
}
|
||||
|
||||
protected override void UnregisterRecipients()
|
||||
{
|
||||
base.UnregisterRecipients();
|
||||
|
||||
Messenger.Unregister<NavigateManageAccountsRequested>(this);
|
||||
Messenger.Unregister<MailtoProtocolMessageRequested>(this);
|
||||
Messenger.Unregister<RefreshUnreadCountsMessage>(this);
|
||||
Messenger.Unregister<AccountsMenuRefreshRequested>(this);
|
||||
Messenger.Unregister<MergedInboxRenamed>(this);
|
||||
Messenger.Unregister<LanguageChanged>(this);
|
||||
Messenger.Unregister<AccountMenuItemsReordered>(this);
|
||||
Messenger.Unregister<AccountSynchronizationProgressUpdatedMessage>(this);
|
||||
Messenger.Unregister<NavigateAppPreferencesRequested>(this);
|
||||
Messenger.Unregister<AccountFolderConfigurationUpdated>(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,4 +39,34 @@ public class MailBaseViewModel : CoreBaseViewModel,
|
||||
|
||||
void IRecipient<FolderRenamed>.Receive(FolderRenamed message) => OnFolderRenamed(message.MailItemFolder);
|
||||
void IRecipient<FolderSynchronizationEnabled>.Receive(FolderSynchronizationEnabled message) => OnFolderSynchronizationEnabled(message.MailItemFolder);
|
||||
|
||||
protected override void RegisterRecipients()
|
||||
{
|
||||
base.RegisterRecipients();
|
||||
|
||||
Messenger.Register<MailAddedMessage>(this);
|
||||
Messenger.Register<MailRemovedMessage>(this);
|
||||
Messenger.Register<MailUpdatedMessage>(this);
|
||||
Messenger.Register<MailDownloadedMessage>(this);
|
||||
Messenger.Register<DraftCreated>(this);
|
||||
Messenger.Register<DraftFailed>(this);
|
||||
Messenger.Register<DraftMapped>(this);
|
||||
Messenger.Register<FolderRenamed>(this);
|
||||
Messenger.Register<FolderSynchronizationEnabled>(this);
|
||||
}
|
||||
|
||||
protected override void UnregisterRecipients()
|
||||
{
|
||||
base.UnregisterRecipients();
|
||||
|
||||
Messenger.Unregister<MailAddedMessage>(this);
|
||||
Messenger.Unregister<MailRemovedMessage>(this);
|
||||
Messenger.Unregister<MailUpdatedMessage>(this);
|
||||
Messenger.Unregister<MailDownloadedMessage>(this);
|
||||
Messenger.Unregister<DraftCreated>(this);
|
||||
Messenger.Unregister<DraftFailed>(this);
|
||||
Messenger.Unregister<DraftMapped>(this);
|
||||
Messenger.Unregister<FolderRenamed>(this);
|
||||
Messenger.Unregister<FolderSynchronizationEnabled>(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1081,4 +1081,34 @@ public partial class MailListPageViewModel : MailBaseViewModel,
|
||||
{
|
||||
// MailCollection.UpdateThumbnails(message.Email);
|
||||
}
|
||||
|
||||
protected override void RegisterRecipients()
|
||||
{
|
||||
base.RegisterRecipients();
|
||||
|
||||
Messenger.Register<MailItemNavigationRequested>(this);
|
||||
Messenger.Register<ActiveMailFolderChangedEvent>(this);
|
||||
Messenger.Register<MailItemSelectedEvent>(this);
|
||||
Messenger.Register<MailItemSelectionRemovedEvent>(this);
|
||||
Messenger.Register<AccountSynchronizationCompleted>(this);
|
||||
Messenger.Register<NewMailSynchronizationRequested>(this);
|
||||
Messenger.Register<AccountSynchronizerStateChanged>(this);
|
||||
Messenger.Register<AccountCacheResetMessage>(this);
|
||||
Messenger.Register<ThumbnailAdded>(this);
|
||||
}
|
||||
|
||||
protected override void UnregisterRecipients()
|
||||
{
|
||||
base.UnregisterRecipients();
|
||||
|
||||
Messenger.Unregister<MailItemNavigationRequested>(this);
|
||||
Messenger.Unregister<ActiveMailFolderChangedEvent>(this);
|
||||
Messenger.Unregister<MailItemSelectedEvent>(this);
|
||||
Messenger.Unregister<MailItemSelectionRemovedEvent>(this);
|
||||
Messenger.Unregister<AccountSynchronizationCompleted>(this);
|
||||
Messenger.Unregister<NewMailSynchronizationRequested>(this);
|
||||
Messenger.Unregister<AccountSynchronizerStateChanged>(this);
|
||||
Messenger.Unregister<AccountCacheResetMessage>(this);
|
||||
Messenger.Unregister<ThumbnailAdded>(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ using Wino.Core.Domain.Interfaces;
|
||||
using Wino.Core.Domain.Models.MailItem;
|
||||
using Wino.Core.Domain.Models.Menus;
|
||||
using Wino.Core.Domain.Models.Navigation;
|
||||
using Wino.Core.Domain.Models.Printing;
|
||||
using Wino.Core.Domain.Models.Reader;
|
||||
using Wino.Core.Services;
|
||||
using Wino.Mail.ViewModels.Data;
|
||||
@@ -55,7 +56,7 @@ public partial class MailRenderingPageViewModel : MailBaseViewModel,
|
||||
// Used in 'Save as' and 'Print' functionality.
|
||||
public Func<string, Task<bool>> SaveHTMLasPDFFunc { get; set; }
|
||||
|
||||
public Action ShowPrintUIAction { get; set; }
|
||||
public Func<WebView2PrintSettingsModel, Task<PrintingResult>> DirectPrintFuncAsync { get; set; }
|
||||
|
||||
#region Properties
|
||||
|
||||
@@ -257,7 +258,22 @@ public partial class MailRenderingPageViewModel : MailBaseViewModel,
|
||||
}
|
||||
else if (operation == MailOperation.Print)
|
||||
{
|
||||
ShowPrintUI();
|
||||
var settings = await _dialogService.ShowPrintDialogAsync();
|
||||
|
||||
if (settings == null) return;
|
||||
|
||||
var printingResult = await DirectPrintFuncAsync.Invoke(settings);
|
||||
|
||||
// TODO: More detailed printing result handling.
|
||||
if (printingResult == PrintingResult.Submitted)
|
||||
{
|
||||
_dialogService.InfoBarMessage(Translator.DialogMessage_PrintingSuccessTitle, Translator.DialogMessage_PrintingSuccessMessage, InfoBarMessageType.Success);
|
||||
}
|
||||
else if (printingResult == PrintingResult.Failed)
|
||||
{
|
||||
_dialogService.InfoBarMessage(Translator.DialogMessage_PrintingFailedTitle, Translator.DialogMessage_PrintingFailedMessage, InfoBarMessageType.Error);
|
||||
}
|
||||
|
||||
}
|
||||
else if (operation == MailOperation.ViewMessageSource)
|
||||
{
|
||||
@@ -682,19 +698,6 @@ public partial class MailRenderingPageViewModel : MailBaseViewModel,
|
||||
}
|
||||
}
|
||||
|
||||
private void ShowPrintUI()
|
||||
{
|
||||
try
|
||||
{
|
||||
ShowPrintUIAction?.Invoke();
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Log.Error(exception, "Failed to print mail.");
|
||||
_dialogService.InfoBarMessage(string.Empty, exception.Message, InfoBarMessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SaveAsAsync()
|
||||
{
|
||||
try
|
||||
@@ -793,4 +796,20 @@ public partial class MailRenderingPageViewModel : MailBaseViewModel,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected override void RegisterRecipients()
|
||||
{
|
||||
base.RegisterRecipients();
|
||||
|
||||
Messenger.Register<NewMailItemRenderingRequestedEvent>(this);
|
||||
Messenger.Register<ThumbnailAdded>(this);
|
||||
}
|
||||
|
||||
protected override void UnregisterRecipients()
|
||||
{
|
||||
base.UnregisterRecipients();
|
||||
|
||||
Messenger.Unregister<NewMailItemRenderingRequestedEvent>(this);
|
||||
Messenger.Unregister<ThumbnailAdded>(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Wino.Mail.WinUI;
|
||||
|
||||
public partial class App : WinoApplication, IRecipient<NewMailSynchronizationRequested>
|
||||
{
|
||||
private ISynchronizationManager _synchronizationManager;
|
||||
private ISynchronizationManager? _synchronizationManager;
|
||||
|
||||
public App()
|
||||
{
|
||||
@@ -23,7 +23,7 @@ public partial class App : WinoApplication, IRecipient<NewMailSynchronizationReq
|
||||
|
||||
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
||||
|
||||
WeakReferenceMessenger.Default.Register<NewMailSynchronizationRequested>(this);
|
||||
RegisterRecipients();
|
||||
}
|
||||
|
||||
#region Dependency Injection
|
||||
@@ -114,8 +114,13 @@ public partial class App : WinoApplication, IRecipient<NewMailSynchronizationReq
|
||||
MainWindow.Activate();
|
||||
}
|
||||
|
||||
private void RegisterRecipients()
|
||||
{
|
||||
WeakReferenceMessenger.Default.Register<NewMailSynchronizationRequested>(this);
|
||||
}
|
||||
|
||||
public void Receive(NewMailSynchronizationRequested message)
|
||||
{
|
||||
_synchronizationManager.SynchronizeMailAsync(message.Options);
|
||||
_synchronizationManager?.SynchronizeMailAsync(message.Options);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Controls.Primitives;
|
||||
using Microsoft.UI.Xaml.Input;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
using Windows.Foundation;
|
||||
using Wino.Core.Domain;
|
||||
using Wino.Core.Domain.Entities.Mail;
|
||||
@@ -20,6 +21,7 @@ using Wino.Core.Domain.Models.Navigation;
|
||||
using Wino.Core.WinUI;
|
||||
using Wino.Core.WinUI.Controls;
|
||||
using Wino.Extensions;
|
||||
using Wino.Mail.ViewModels.Data;
|
||||
using Wino.MenuFlyouts;
|
||||
using Wino.MenuFlyouts.Context;
|
||||
using Wino.Messaging.Client.Accounts;
|
||||
@@ -37,13 +39,27 @@ public sealed partial class AppShell : AppShellAbstract,
|
||||
IRecipient<InfoBarMessageRequested>
|
||||
{
|
||||
[GeneratedDependencyProperty]
|
||||
public partial UIElement TopShellContent { get; set; }
|
||||
public partial UIElement? TopShellContent { get; set; }
|
||||
|
||||
public AppShell() : base()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
public Frame GetShellFrame() => ShellFrame;
|
||||
|
||||
//protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||
//{
|
||||
// base.OnNavigatedTo(e);
|
||||
|
||||
// WeakReferenceMessenger.Default.Register<InfoBarMessageRequested>(this);
|
||||
// WeakReferenceMessenger.Default.Register<AccountMenuItemExtended>(this);
|
||||
// WeakReferenceMessenger.Default.Register<CreateNewMailWithMultipleAccountsRequested>(this);
|
||||
// WeakReferenceMessenger.Default.Register<NavigateMailFolderEvent>(this);
|
||||
//}
|
||||
|
||||
protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
|
||||
{
|
||||
base.OnNavigatingFrom(e);
|
||||
}
|
||||
|
||||
private async void ItemDroppedOnFolder(object sender, DragEventArgs e)
|
||||
{
|
||||
@@ -66,14 +82,14 @@ public sealed partial class AppShell : AppShellAbstract,
|
||||
|
||||
foreach (var item in dragPackage.DraggingMails)
|
||||
{
|
||||
//if (item is MailItemViewModel singleMailItemViewModel)
|
||||
//{
|
||||
// mailCopies.Add(singleMailItemViewModel.MailCopy);
|
||||
//}
|
||||
//else if (item is ThreadMailItemViewModel threadViewModel)
|
||||
//{
|
||||
// mailCopies.AddRange(threadViewModel.GetMailCopies());
|
||||
//}
|
||||
if (item is MailItemViewModel singleMailItemViewModel)
|
||||
{
|
||||
mailCopies.Add(singleMailItemViewModel.MailCopy);
|
||||
}
|
||||
else if (item is ThreadMailItemViewModel threadViewModel)
|
||||
{
|
||||
mailCopies.AddRange(threadViewModel.ThreadEmails.Select(a => a.MailCopy));
|
||||
}
|
||||
}
|
||||
|
||||
await ViewModel.PerformMoveOperationAsync(mailCopies, draggingFolder);
|
||||
@@ -114,7 +130,7 @@ public sealed partial class AppShell : AppShellAbstract,
|
||||
// Check whether the moving item's account has at least one same as the target folder's account.
|
||||
var draggedAccountIds = folderMenuItem.HandlingFolders.Select(a => a.MailAccountId);
|
||||
|
||||
if (!dragPackage.DraggingMails.Any(a => draggedAccountIds.Contains(a.AssignedAccount.Id))) return false;
|
||||
if (!dragPackage.DraggingMails.Cast<MailCopy>().Any(a => draggedAccountIds.Contains(a.AssignedAccount.Id))) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -320,4 +336,24 @@ public sealed partial class AppShell : AppShellAbstract,
|
||||
ShellFrame.Margin = new Thickness(0);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void RegisterRecipients()
|
||||
{
|
||||
base.RegisterRecipients();
|
||||
|
||||
WeakReferenceMessenger.Default.Register<InfoBarMessageRequested>(this);
|
||||
WeakReferenceMessenger.Default.Register<AccountMenuItemExtended>(this);
|
||||
WeakReferenceMessenger.Default.Register<CreateNewMailWithMultipleAccountsRequested>(this);
|
||||
WeakReferenceMessenger.Default.Register<NavigateMailFolderEvent>(this);
|
||||
}
|
||||
|
||||
protected override void UnregisterRecipients()
|
||||
{
|
||||
base.UnregisterRecipients();
|
||||
|
||||
WeakReferenceMessenger.Default.Unregister<InfoBarMessageRequested>(this);
|
||||
WeakReferenceMessenger.Default.Unregister<AccountMenuItemExtended>(this);
|
||||
WeakReferenceMessenger.Default.Unregister<CreateNewMailWithMultipleAccountsRequested>(this);
|
||||
WeakReferenceMessenger.Default.Unregister<NavigateMailFolderEvent>(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,9 +103,19 @@ public sealed partial class NewImapSetupDialog : ContentDialog,
|
||||
public void StartImapConnectionSetup(MailAccount account) => ImapFrame.Navigate(typeof(WelcomeImapSetupPage), account, new DrillInNavigationTransitionInfo());
|
||||
public void StartImapConnectionSetup(AccountCreationDialogResult accountCreationDialogResult) => ImapFrame.Navigate(typeof(WelcomeImapSetupPage), accountCreationDialogResult, new DrillInNavigationTransitionInfo());
|
||||
|
||||
private void ImapSetupDialogClosed(ContentDialog sender, ContentDialogClosedEventArgs args) => WeakReferenceMessenger.Default.UnregisterAll(this);
|
||||
private void ImapSetupDialogClosed(ContentDialog sender, ContentDialogClosedEventArgs args)
|
||||
{
|
||||
WeakReferenceMessenger.Default.Unregister<ImapSetupNavigationRequested>(this);
|
||||
WeakReferenceMessenger.Default.Unregister<ImapSetupBackNavigationRequested>(this);
|
||||
WeakReferenceMessenger.Default.Unregister<ImapSetupDismissRequested>(this);
|
||||
}
|
||||
|
||||
private void ImapSetupDialogOpened(ContentDialog sender, ContentDialogOpenedEventArgs args) => WeakReferenceMessenger.Default.RegisterAll(this);
|
||||
private void ImapSetupDialogOpened(ContentDialog sender, ContentDialogOpenedEventArgs args)
|
||||
{
|
||||
WeakReferenceMessenger.Default.Register<ImapSetupNavigationRequested>(this);
|
||||
WeakReferenceMessenger.Default.Register<ImapSetupBackNavigationRequested>(this);
|
||||
WeakReferenceMessenger.Default.Register<ImapSetupDismissRequested>(this);
|
||||
}
|
||||
|
||||
// Don't hide the dialog unless dismiss is requested from the inner pages specifically.
|
||||
private void OnDialogClosing(ContentDialog sender, ContentDialogClosingEventArgs args) => args.Cancel = !isDismissRequested;
|
||||
|
||||
@@ -15,7 +15,7 @@ using WinUIEx;
|
||||
|
||||
namespace Wino.Mail.WinUI;
|
||||
|
||||
public sealed partial class ShellWindow : WindowEx, IWinoShellWindow, IRecipient<ApplicationThemeChanged>
|
||||
public sealed partial class ShellWindow : WindowEx, IWinoShellWindow, IRecipient<ApplicationThemeChanged>, IRecipient<TitleBarShellContentUpdated>
|
||||
{
|
||||
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.");
|
||||
@@ -23,8 +23,7 @@ public sealed partial class ShellWindow : WindowEx, IWinoShellWindow, IRecipient
|
||||
|
||||
public ShellWindow()
|
||||
{
|
||||
WeakReferenceMessenger.Default.Register<TitleBarShellContentUpdated>(this);
|
||||
WeakReferenceMessenger.Default.Register<ApplicationThemeChanged>(this);
|
||||
RegisterRecipients();
|
||||
|
||||
InitializeComponent();
|
||||
|
||||
@@ -177,10 +176,24 @@ public sealed partial class ShellWindow : WindowEx, IWinoShellWindow, IRecipient
|
||||
// Clean up system tray
|
||||
_systemTrayService?.Dispose();
|
||||
|
||||
UnregisterRecipients();
|
||||
|
||||
// Close the window
|
||||
this.Close();
|
||||
|
||||
// Exit the application
|
||||
Application.Current.Exit();
|
||||
}
|
||||
|
||||
private void RegisterRecipients()
|
||||
{
|
||||
WeakReferenceMessenger.Default.Register<TitleBarShellContentUpdated>(this);
|
||||
WeakReferenceMessenger.Default.Register<ApplicationThemeChanged>(this);
|
||||
}
|
||||
|
||||
private void UnregisterRecipients()
|
||||
{
|
||||
WeakReferenceMessenger.Default.Unregister<TitleBarShellContentUpdated>(this);
|
||||
WeakReferenceMessenger.Default.Unregister<ApplicationThemeChanged>(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,22 +57,12 @@ public sealed partial class MailListPage : MailListPageAbstract,
|
||||
{
|
||||
WeakReferenceMessenger.Default.Send(new ActiveMailFolderChangedEvent(folderNavigationArgs.BaseFolderMenuItem, folderNavigationArgs.FolderInitLoadAwaitTask));
|
||||
}
|
||||
|
||||
WeakReferenceMessenger.Default.Register<ClearMailSelectionsRequested>(this);
|
||||
WeakReferenceMessenger.Default.Register<ActiveMailItemChangedEvent>(this);
|
||||
WeakReferenceMessenger.Default.Register<SelectMailItemContainerEvent>(this);
|
||||
WeakReferenceMessenger.Default.Register<DisposeRenderingFrameRequested>(this);
|
||||
}
|
||||
|
||||
protected override void OnNavigatedFrom(NavigationEventArgs e)
|
||||
{
|
||||
base.OnNavigatedFrom(e);
|
||||
|
||||
WeakReferenceMessenger.Default.Unregister<ClearMailSelectionsRequested>(this);
|
||||
WeakReferenceMessenger.Default.Unregister<ActiveMailItemChangedEvent>(this);
|
||||
WeakReferenceMessenger.Default.Unregister<SelectMailItemContainerEvent>(this);
|
||||
WeakReferenceMessenger.Default.Unregister<DisposeRenderingFrameRequested>(this);
|
||||
|
||||
// Dispose all WinoListView items.
|
||||
|
||||
// MailListView.Dispose();
|
||||
@@ -455,6 +445,22 @@ public sealed partial class MailListPage : MailListPageAbstract,
|
||||
ViewModel.NavigationService.Navigate(WinoPage.IdlePage, null, NavigationReferenceFrame.RenderingFrame, NavigationTransitionType.DrillIn);
|
||||
}
|
||||
|
||||
protected override void RegisterRecipients()
|
||||
{
|
||||
WeakReferenceMessenger.Default.Register<ClearMailSelectionsRequested>(this);
|
||||
WeakReferenceMessenger.Default.Register<ActiveMailItemChangedEvent>(this);
|
||||
WeakReferenceMessenger.Default.Register<SelectMailItemContainerEvent>(this);
|
||||
WeakReferenceMessenger.Default.Register<DisposeRenderingFrameRequested>(this);
|
||||
}
|
||||
|
||||
protected override void UnregisterRecipients()
|
||||
{
|
||||
WeakReferenceMessenger.Default.Unregister<ClearMailSelectionsRequested>(this);
|
||||
WeakReferenceMessenger.Default.Unregister<ActiveMailItemChangedEvent>(this);
|
||||
WeakReferenceMessenger.Default.Unregister<SelectMailItemContainerEvent>(this);
|
||||
WeakReferenceMessenger.Default.Unregister<DisposeRenderingFrameRequested>(this);
|
||||
}
|
||||
|
||||
private void PageSizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
ViewModel.MaxMailListLength = e.NewSize.Width - RENDERING_COLUMN_MIN_WIDTH;
|
||||
|
||||
@@ -11,7 +11,9 @@ using Microsoft.UI.Xaml.Navigation;
|
||||
using Microsoft.Web.WebView2.Core;
|
||||
using Windows.System;
|
||||
using Wino.Core.Domain;
|
||||
using Wino.Core.Domain.Enums;
|
||||
using Wino.Core.Domain.Interfaces;
|
||||
using Wino.Core.Domain.Models.Printing;
|
||||
using Wino.Core.WinUI.Extensions;
|
||||
using Wino.Mail.ViewModels.Data;
|
||||
using Wino.Mail.WinUI;
|
||||
@@ -43,7 +45,7 @@ public sealed partial class MailRenderingPage : MailRenderingPageAbstract,
|
||||
Environment.SetEnvironmentVariable("WEBVIEW2_DEFAULT_BACKGROUND_COLOR", "00FFFFFF");
|
||||
Environment.SetEnvironmentVariable("WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS", "--enable-features=OverlayScrollbar,msOverlayScrollbarWinStyle,msOverlayScrollbarWinStyleAnimation,msWebView2CodeCache");
|
||||
|
||||
ViewModel.ShowPrintUIAction = ShowPrintUI;
|
||||
ViewModel.DirectPrintFuncAsync = DirectPrintAsync;
|
||||
|
||||
ViewModel.SaveHTMLasPDFFunc = new Func<string, Task<bool>>((path) =>
|
||||
{
|
||||
@@ -51,19 +53,25 @@ public sealed partial class MailRenderingPage : MailRenderingPageAbstract,
|
||||
});
|
||||
}
|
||||
|
||||
private async void ShowPrintUI()
|
||||
private async Task<PrintingResult> DirectPrintAsync(WebView2PrintSettingsModel settings)
|
||||
{
|
||||
if (Chromium.CoreWebView2 == null) return;
|
||||
if (Chromium.CoreWebView2 == null) return PrintingResult.Failed;
|
||||
|
||||
// TODO: Footer still shows wino.mail/html, there is no way to change it currently.
|
||||
// TODO: ShowPrintUI - System doesn't open.
|
||||
// TODO: ShowPrintUI - System doesn't open.
|
||||
try
|
||||
{
|
||||
var nativeSettings = settings.ToCoreWebView2PrintSettings(Chromium.CoreWebView2.Environment);
|
||||
var res = await Chromium.CoreWebView2.PrintAsync(nativeSettings);
|
||||
|
||||
// Set the document title before printing. This title will be used in the print dialog and header.
|
||||
await Chromium.CoreWebView2.ExecuteScriptAsync($"document.title = '{ViewModel.Subject}';");
|
||||
var settings = Chromium.CoreWebView2.Environment.CreatePrintSettings();
|
||||
|
||||
Chromium.CoreWebView2?.ShowPrintUI(CoreWebView2PrintDialogKind.System);
|
||||
return res switch
|
||||
{
|
||||
CoreWebView2PrintStatus.Succeeded => PrintingResult.Submitted,
|
||||
_ => PrintingResult.Failed,
|
||||
};
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return PrintingResult.Failed;
|
||||
}
|
||||
}
|
||||
|
||||
public override async void OnEditorThemeChanged()
|
||||
@@ -138,10 +146,6 @@ public sealed partial class MailRenderingPage : MailRenderingPageAbstract,
|
||||
{
|
||||
base.OnNavigatedFrom(e);
|
||||
|
||||
WeakReferenceMessenger.Default.Unregister<HtmlRenderingRequested>(this);
|
||||
WeakReferenceMessenger.Default.Unregister<CancelRenderingContentRequested>(this);
|
||||
WeakReferenceMessenger.Default.Unregister<ApplicationThemeChanged>(this);
|
||||
|
||||
// Disposing the page.
|
||||
// Make sure the WebView2 is disposed properly.
|
||||
|
||||
@@ -171,10 +175,6 @@ public sealed partial class MailRenderingPage : MailRenderingPageAbstract,
|
||||
{
|
||||
base.OnNavigatedTo(e);
|
||||
|
||||
WeakReferenceMessenger.Default.Register<HtmlRenderingRequested>(this);
|
||||
WeakReferenceMessenger.Default.Register<CancelRenderingContentRequested>(this);
|
||||
WeakReferenceMessenger.Default.Register<ApplicationThemeChanged>(this);
|
||||
|
||||
var anim = ConnectedAnimationService.GetForCurrentView().GetAnimation("WebViewConnectedAnimation");
|
||||
anim?.TryStart(Chromium);
|
||||
|
||||
@@ -297,4 +297,22 @@ public sealed partial class MailRenderingPage : MailRenderingPageAbstract,
|
||||
hyperlinkButton.ContextFlyout.ShowAt(hyperlinkButton);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void RegisterRecipients()
|
||||
{
|
||||
base.RegisterRecipients();
|
||||
|
||||
WeakReferenceMessenger.Default.Register<HtmlRenderingRequested>(this);
|
||||
WeakReferenceMessenger.Default.Register<CancelRenderingContentRequested>(this);
|
||||
WeakReferenceMessenger.Default.Register<ApplicationThemeChanged>(this);
|
||||
}
|
||||
|
||||
protected override void UnregisterRecipients()
|
||||
{
|
||||
base.UnregisterRecipients();
|
||||
|
||||
WeakReferenceMessenger.Default.Unregister<HtmlRenderingRequested>(this);
|
||||
WeakReferenceMessenger.Default.Unregister<CancelRenderingContentRequested>(this);
|
||||
WeakReferenceMessenger.Default.Unregister<ApplicationThemeChanged>(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -332,4 +332,24 @@ public sealed partial class AppShell : AppShellAbstract,
|
||||
ShellFrame.Margin = new Thickness(0);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void RegisterRecipients()
|
||||
{
|
||||
base.RegisterRecipients();
|
||||
|
||||
WeakReferenceMessenger.Default.Register<InfoBarMessageRequested>(this);
|
||||
WeakReferenceMessenger.Default.Register<AccountMenuItemExtended>(this);
|
||||
WeakReferenceMessenger.Default.Register<CreateNewMailWithMultipleAccountsRequested>(this);
|
||||
WeakReferenceMessenger.Default.Register<NavigateMailFolderEvent>(this);
|
||||
}
|
||||
|
||||
protected override void UnregisterRecipients()
|
||||
{
|
||||
base.UnregisterRecipients();
|
||||
|
||||
WeakReferenceMessenger.Default.Unregister<InfoBarMessageRequested>(this);
|
||||
WeakReferenceMessenger.Default.Unregister<AccountMenuItemExtended>(this);
|
||||
WeakReferenceMessenger.Default.Unregister<CreateNewMailWithMultipleAccountsRequested>(this);
|
||||
WeakReferenceMessenger.Default.Unregister<NavigateMailFolderEvent>(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,9 +102,19 @@ public sealed partial class NewImapSetupDialog : ContentDialog,
|
||||
public void StartImapConnectionSetup(MailAccount account) => ImapFrame.Navigate(typeof(WelcomeImapSetupPage), account, new DrillInNavigationTransitionInfo());
|
||||
public void StartImapConnectionSetup(AccountCreationDialogResult accountCreationDialogResult) => ImapFrame.Navigate(typeof(WelcomeImapSetupPage), accountCreationDialogResult, new DrillInNavigationTransitionInfo());
|
||||
|
||||
private void ImapSetupDialogClosed(ContentDialog sender, ContentDialogClosedEventArgs args) => WeakReferenceMessenger.Default.UnregisterAll(this);
|
||||
private void ImapSetupDialogClosed(ContentDialog sender, ContentDialogClosedEventArgs args)
|
||||
{
|
||||
WeakReferenceMessenger.Default.Unregister<ImapSetupNavigationRequested>(this);
|
||||
WeakReferenceMessenger.Default.Unregister<ImapSetupBackNavigationRequested>(this);
|
||||
WeakReferenceMessenger.Default.Unregister<ImapSetupDismissRequested>(this);
|
||||
}
|
||||
|
||||
private void ImapSetupDialogOpened(ContentDialog sender, ContentDialogOpenedEventArgs args) => WeakReferenceMessenger.Default.RegisterAll(this);
|
||||
private void ImapSetupDialogOpened(ContentDialog sender, ContentDialogOpenedEventArgs args)
|
||||
{
|
||||
WeakReferenceMessenger.Default.Register<ImapSetupNavigationRequested>(this);
|
||||
WeakReferenceMessenger.Default.Register<ImapSetupBackNavigationRequested>(this);
|
||||
WeakReferenceMessenger.Default.Register<ImapSetupDismissRequested>(this);
|
||||
}
|
||||
|
||||
// Don't hide the dialog unless dismiss is requested from the inner pages specifically.
|
||||
private void OnDialogClosing(ContentDialog sender, ContentDialogClosingEventArgs args) => args.Cancel = !isDismissRequested;
|
||||
|
||||
Reference in New Issue
Block a user