Merge branch 'feature/EventCompose' into feature/vNext

This commit is contained in:
Burak Kaan Köse
2026-03-07 01:46:21 +01:00
46 changed files with 2650 additions and 114 deletions
+1
View File
@@ -171,6 +171,7 @@ public partial class App : WinoApplication,
services.AddTransient(typeof(CalendarSettingsPageViewModel));
services.AddTransient(typeof(CalendarAccountSettingsPageViewModel));
services.AddTransient(typeof(EventDetailsPageViewModel));
services.AddTransient(typeof(CalendarEventComposePageViewModel));
}
#endregion
@@ -14,7 +14,6 @@ using Wino.Core.Domain;
using Wino.Core.Domain.Enums;
using Wino.Core.Domain.Interfaces;
using Wino.Core.Domain.Models.MailItem;
using Wino.Helpers;
using Wino.Mail.ViewModels.Data;
using Wino.Mail.WinUI;
@@ -176,7 +175,7 @@ public sealed partial class CalendarMailItemDisplayInformationControl : UserCont
}
using var stream = new MemoryStream();
calendarMimePart.Content.DecodeTo(stream);
calendarMimePart.Content?.DecodeTo(stream);
var contentBytes = stream.ToArray();
if (contentBytes.Length == 0)
@@ -9,6 +9,7 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media.Imaging;
using Wino.Core.Domain.Entities.Shared;
using Wino.Core.Domain.Interfaces;
using Wino.Mail.WinUI;
@@ -30,6 +31,15 @@ public sealed partial class ImagePreviewControl : PersonPicture
[GeneratedDependencyProperty]
public partial IMailItemDisplayInformation? MailItemInformation { get; set; }
[GeneratedDependencyProperty]
public partial AccountContact? PreviewContact { get; set; }
[GeneratedDependencyProperty]
public partial string? Address { get; set; }
[GeneratedDependencyProperty]
public partial string? DisplayNameOverride { get; set; }
private readonly IThumbnailService? _thumbnailService;
private readonly IPreferencesService? _preferencesService;
private readonly IContactPictureFileService? _contactPictureFileService;
@@ -73,6 +83,11 @@ public sealed partial class ImagePreviewControl : PersonPicture
RequestRefresh();
}
partial void OnPreviewContactPropertyChanged(DependencyPropertyChangedEventArgs e) => RequestRefresh();
partial void OnAddressPropertyChanged(DependencyPropertyChangedEventArgs e) => RequestRefresh();
partial void OnDisplayNameOverridePropertyChanged(DependencyPropertyChangedEventArgs e) => RequestRefresh();
private void OnLoaded(object sender, RoutedEventArgs e)
{
RequestRefresh();
@@ -262,7 +277,7 @@ public sealed partial class ImagePreviewControl : PersonPicture
var address = ResolveAddress();
var displayName = ResolveDisplayName(address);
var base64Picture = ResolveBase64Picture();
var contactPictureFileId = MailItemInformation?.SenderContact?.ContactPictureFileId;
var contactPictureFileId = PreviewContact?.ContactPictureFileId ?? MailItemInformation?.SenderContact?.ContactPictureFileId;
return new RefreshSnapshot(displayName, address, contactPictureFileId, base64Picture);
}).ConfigureAwait(false);
@@ -270,6 +285,12 @@ public sealed partial class ImagePreviewControl : PersonPicture
private string ResolveAddress()
{
if (!string.IsNullOrWhiteSpace(PreviewContact?.Address))
return PreviewContact.Address.Trim();
if (!string.IsNullOrWhiteSpace(Address))
return Address.Trim();
if (MailItemInformation == null)
return string.Empty;
@@ -285,6 +306,12 @@ public sealed partial class ImagePreviewControl : PersonPicture
private string ResolveDisplayName(string resolvedAddress)
{
if (!string.IsNullOrWhiteSpace(PreviewContact?.Name))
return PreviewContact.Name.Trim();
if (!string.IsNullOrWhiteSpace(DisplayNameOverride))
return DisplayNameOverride.Trim();
var contactName = MailItemInformation?.SenderContact?.Name;
if (!string.IsNullOrWhiteSpace(contactName))
return contactName.Trim();
@@ -297,6 +324,9 @@ public sealed partial class ImagePreviewControl : PersonPicture
private string ResolveBase64Picture()
{
if (!string.IsNullOrWhiteSpace(PreviewContact?.Base64ContactPicture))
return PreviewContact.Base64ContactPicture;
if (!string.IsNullOrWhiteSpace(MailItemInformation?.SenderContact?.Base64ContactPicture))
return MailItemInformation.SenderContact.Base64ContactPicture;
@@ -0,0 +1,73 @@
<ContentDialog
x:Class="Wino.Dialogs.SingleCalendarPickerDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:calendar="using:Wino.Core.Domain.Models.Calendar"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:domain="using:Wino.Core.Domain"
xmlns:helpers="using:Wino.Helpers"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:sharedCalendar="using:Wino.Core.Domain.Entities.Calendar"
Title="{x:Bind domain:Translator.CalendarEventCompose_PickCalendarTitle}"
PrimaryButtonText="{x:Bind domain:Translator.Buttons_Cancel}"
Style="{StaticResource WinoDialogStyle}"
mc:Ignorable="d">
<ContentDialog.Resources>
<x:Double x:Key="ContentDialogMinWidth">420</x:Double>
<Style
x:Key="CalendarPickerListItemStyle"
BasedOn="{StaticResource DefaultListViewItemStyle}"
TargetType="ListViewItem">
<Setter Property="Padding" Value="12,10" />
<Setter Property="CornerRadius" Value="4" />
<Setter Property="Margin" Value="0,2" />
</Style>
</ContentDialog.Resources>
<ScrollViewer Margin="0,8,0,0">
<ItemsControl ItemsSource="{x:Bind AvailableGroups}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="calendar:CalendarPickerAccountGroup">
<StackPanel Margin="0,0,0,12" Spacing="6">
<TextBlock FontWeight="SemiBold">
<Run Text="{x:Bind Account.Name}" />
<Run Text=" (" />
<Run Text="{x:Bind Account.Address}" />
<Run Text=")" />
</TextBlock>
<ListView
IsItemClickEnabled="True"
ItemClick="CalendarClicked"
ItemContainerStyle="{StaticResource CalendarPickerListItemStyle}"
ItemsSource="{x:Bind Calendars}"
SelectionMode="None">
<ListView.ItemTemplate>
<DataTemplate x:DataType="sharedCalendar:AccountCalendar">
<Grid ColumnSpacing="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Ellipse
Width="14"
Height="14"
VerticalAlignment="Center"
Fill="{x:Bind helpers:XamlHelpers.GetSolidColorBrushFromHex(BackgroundColorHex), Mode=OneWay}" />
<TextBlock
Grid.Column="1"
VerticalAlignment="Center"
Text="{x:Bind Name}" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</ContentDialog>
@@ -0,0 +1,26 @@
using System.Collections.Generic;
using Microsoft.UI.Xaml.Controls;
using Wino.Core.Domain.Entities.Calendar;
using Wino.Core.Domain.Models.Calendar;
namespace Wino.Dialogs;
public sealed partial class SingleCalendarPickerDialog : ContentDialog
{
public AccountCalendar? PickedCalendar { get; private set; }
public List<CalendarPickerAccountGroup> AvailableGroups { get; } = [];
public SingleCalendarPickerDialog(List<CalendarPickerAccountGroup> availableGroups)
{
AvailableGroups = availableGroups;
InitializeComponent();
}
private void CalendarClicked(object sender, ItemClickEventArgs e)
{
PickedCalendar = e.ClickedItem as AccountCalendar;
Hide();
}
}
+1
View File
@@ -157,6 +157,7 @@
<coreControls:WinoFontIcon Icon="NewMail" />
</muxc:NavigationViewItem.Icon>
<TextBlock
Margin="0,-2,0,0"
VerticalAlignment="Center"
FontSize="16"
Style="{StaticResource FlyoutPickerTitleTextBlockStyle}"
+14
View File
@@ -6,12 +6,14 @@ using CommunityToolkit.Mvvm.Messaging;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Wino.Core.Domain;
using Wino.Core.Domain.Entities.Calendar;
using Wino.Core.Domain.Entities.Mail;
using Wino.Core.Domain.Entities.Shared;
using Wino.Core.Domain.Enums;
using Wino.Core.Domain.Interfaces;
using Wino.Core.Domain.Models;
using Wino.Core.Domain.Models.Accounts;
using Wino.Core.Domain.Models.Calendar;
using Wino.Core.Domain.Models.Folders;
using Wino.Core.Domain.Models.Synchronization;
using Wino.Mail.WinUI.Extensions;
@@ -122,6 +124,18 @@ public class DialogService : DialogServiceBase, IMailDialogService
return accountPicker.PickedAccount ?? null!;
}
public async Task<AccountCalendar> ShowSingleCalendarPickerDialogAsync(List<CalendarPickerAccountGroup> availableCalendarGroups)
{
var calendarPicker = new SingleCalendarPickerDialog(availableCalendarGroups)
{
RequestedTheme = ThemeService.RootTheme.ToWindowsElementTheme()
};
await HandleDialogPresentationAsync(calendarPicker);
return calendarPicker.PickedCalendar ?? null!;
}
public async Task<AccountSignature> ShowSignatureEditorDialog(AccountSignature? signatureModel = null)
{
SignatureEditorDialog signatureEditorDialog;
@@ -120,6 +120,40 @@ public class DialogServiceBase : IDialogServiceBase
return returnList;
}
public async Task<List<PickedFileMetadata>> PickFilesMetadataAsync(params object[] typeFilters)
{
var returnList = new List<PickedFileMetadata>();
var picker = new FileOpenPicker
{
ViewMode = PickerViewMode.Thumbnail,
SuggestedStartLocation = PickerLocationId.Desktop
};
foreach (var filter in typeFilters)
{
picker.FileTypeFilter.Add(filter.ToString());
}
var mainWindow = WinoApplication.MainWindow;
if (mainWindow == null) return returnList;
nint windowHandle = WindowNative.GetWindowHandle(mainWindow);
InitializeWithWindow.Initialize(picker, windowHandle);
var files = await picker.PickMultipleFilesAsync();
if (files == null) return returnList;
foreach (var file in files)
{
StorageApplicationPermissions.FutureAccessList.Add(file);
var basicProperties = await file.GetBasicPropertiesAsync();
returnList.Add(new PickedFileMetadata(file.Path, (long)basicProperties.Size));
}
return returnList;
}
private async Task<StorageFile?> PickFileAsync(params object[] typeFilters)
{
var picker = new FileOpenPicker
@@ -55,7 +55,8 @@ public class NavigationService : NavigationServiceBase, INavigationService
private static readonly WinoPage[] CalendarOnlyPages =
[
WinoPage.CalendarPage,
WinoPage.EventDetailsPage
WinoPage.EventDetailsPage,
WinoPage.CalendarEventComposePage
];
public NavigationService(IStatePersistanceService statePersistanceService, IDispatcher dispatcher, IWinoWindowManager windowManager)
@@ -126,6 +127,7 @@ public class NavigationService : NavigationServiceBase, INavigationService
WinoPage.SpecialImapCredentialsPage => typeof(SpecialImapCredentialsPage),
WinoPage.CalendarPage => typeof(CalendarPage),
WinoPage.EventDetailsPage => typeof(EventDetailsPage),
WinoPage.CalendarEventComposePage => typeof(CalendarEventComposePage),
WinoPage.CalendarSettingsPage => typeof(CalendarSettingsPage),
WinoPage.CalendarAccountSettingsPage => typeof(CalendarAccountSettingsPage),
_ => null,
@@ -248,7 +250,7 @@ public class NavigationService : NavigationServiceBase, INavigationService
}
_statePersistanceService.IsReadingMail = _renderingPageTypes.Contains(page);
_statePersistanceService.IsEventDetailsVisible = page == WinoPage.EventDetailsPage;
_statePersistanceService.IsEventDetailsVisible = page == WinoPage.EventDetailsPage || page == WinoPage.CalendarEventComposePage;
Frame? innerShellFrame = GetCoreFrameInternal(NavigationReferenceFrame.InnerShellFrame);
if (innerShellFrame == null && frame == NavigationReferenceFrame.ShellFrame)
@@ -290,6 +290,18 @@ public class PreferencesService(IConfigurationService configurationService) : Ob
set => SaveProperty(propertyName: nameof(DefaultSnoozeDurationInMinutes), value);
}
public NewEventButtonBehavior NewEventButtonBehavior
{
get => _configurationService.Get(nameof(NewEventButtonBehavior), NewEventButtonBehavior.AskEachTime);
set => SetPropertyAndSave(nameof(NewEventButtonBehavior), value);
}
public Guid? DefaultNewEventCalendarId
{
get => _configurationService.Get<Guid?>(nameof(DefaultNewEventCalendarId), null);
set => SetPropertyAndSave(nameof(DefaultNewEventCalendarId), value);
}
public int EmailSyncIntervalMinutes
{
get => _configurationService.Get(nameof(EmailSyncIntervalMinutes), 3);
@@ -9,7 +9,7 @@
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:WebViewEditorControl">
<Grid CornerRadius="3">
<Grid CornerRadius="{StaticResource ControlCornerRadius}">
<Grid Background="White" Visibility="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=IsEditorDarkMode, Mode=OneWay, Converter={StaticResource ReverseBooleanToVisibilityConverter}}" />
<WebView2 x:Name="WebView" />
</Grid>
@@ -0,0 +1,5 @@
using Wino.Calendar.ViewModels;
namespace Wino.Mail.WinUI.Views.Abstract;
public abstract class CalendarEventComposePageAbstract : BasePage<CalendarEventComposePageViewModel> { }
@@ -14,6 +14,7 @@
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:interfaces="using:Wino.Core.Domain.Interfaces"
xmlns:local="using:Wino.Views"
xmlns:mailViewModels="using:Wino.Mail.ViewModels"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
xmlns:ui="using:CommunityToolkit.WinUI"
@@ -50,7 +51,7 @@
VerticalAlignment="Center"
Checked="SyncFolderToggled"
IsChecked="{x:Bind IsSynchronizationEnabled, Mode=OneWay}"
Tag="{Binding}"
Tag="{x:Bind}"
Unchecked="SyncFolderToggled"
Visibility="{x:Bind IsMoveTarget}" />
@@ -61,7 +62,7 @@
VerticalAlignment="Center"
Checked="UnreadBadgeCheckboxToggled"
IsChecked="{x:Bind ShowUnreadCount, Mode=OneWay}"
Tag="{Binding}"
Tag="{x:Bind}"
Unchecked="UnreadBadgeCheckboxToggled"
Visibility="{x:Bind IsMoveTarget}" />
</Grid>
@@ -296,27 +297,72 @@
Visibility="Collapsed">
<StackPanel MaxWidth="900" Spacing="12">
<controls:SettingsCard Description="{x:Bind domain:Translator.CalendarAccountSettings_PrimaryCalendarDescription, Mode=OneTime}" Header="{x:Bind domain:Translator.CalendarAccountSettings_PrimaryCalendar, Mode=OneTime}">
<controls:SettingsCard.HeaderIcon>
<FontIcon Glyph="&#xE735;" />
</controls:SettingsCard.HeaderIcon>
<ComboBox ItemsSource="{x:Bind ViewModel.AccountCalendars, Mode=OneWay}" SelectedItem="{x:Bind ViewModel.SelectedPrimaryCalendar, Mode=TwoWay}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="calendar:AccountCalendar">
<TextBlock Text="{x:Bind Name}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</controls:SettingsCard>
<!-- Calendars List -->
<ItemsControl ItemsSource="{x:Bind ViewModel.AccountCalendars, Mode=OneWay}">
<ItemsControl ItemsSource="{x:Bind ViewModel.AccountCalendarSettingsItems, Mode=OneWay}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="calendar:AccountCalendar">
<controls:SettingsCard
Margin="0,0,0,4"
ActionIcon="{ui:FontIcon Glyph=&#xE974;}"
Click="CalendarItemClicked"
CommandParameter="{x:Bind}"
<DataTemplate x:DataType="mailViewModels:AccountCalendarSettingsItemViewModel">
<controls:SettingsExpander
Margin="0,0,0,8"
Description="{x:Bind TimeZone, Mode=OneWay}"
Header="{x:Bind Name, Mode=OneWay}"
IsClickEnabled="True">
<controls:SettingsCard.HeaderIcon>
<FontIcon Glyph="&#xE163;" />
</controls:SettingsCard.HeaderIcon>
<Border
Width="32"
Height="32"
Background="{x:Bind BackgroundColorHex, Mode=OneWay}"
CornerRadius="4" />
</controls:SettingsCard>
IsExpanded="False">
<controls:SettingsExpander.HeaderIcon>
<SymbolIcon Foreground="{x:Bind helpers:XamlHelpers.GetSolidColorBrushFromHex(BackgroundColorHex), Mode=OneWay}" Symbol="Calendar" />
</controls:SettingsExpander.HeaderIcon>
<controls:SettingsExpander.Items>
<controls:SettingsCard Description="{x:Bind domain:Translator.CalendarAccountSettings_AccountColorDescription, Mode=OneTime}" Header="{x:Bind domain:Translator.CalendarAccountSettings_AccountColor, Mode=OneTime}">
<controls:SettingsCard.HeaderIcon>
<FontIcon Glyph="&#xE790;" />
</controls:SettingsCard.HeaderIcon>
<Border
Width="32"
Height="32"
Background="{x:Bind helpers:XamlHelpers.GetSolidColorBrushFromHex(BackgroundColorHex), Mode=OneWay}"
CornerRadius="4" />
</controls:SettingsCard>
<controls:SettingsCard Description="{x:Bind domain:Translator.CalendarAccountSettings_SyncEnabledDescription, Mode=OneTime}" Header="{x:Bind domain:Translator.CalendarAccountSettings_SyncEnabled, Mode=OneTime}">
<controls:SettingsCard.HeaderIcon>
<FontIcon Glyph="&#xE895;" />
</controls:SettingsCard.HeaderIcon>
<ToggleSwitch
IsOn="{x:Bind IsSynchronizationEnabled, Mode=OneWay}"
Tag="{x:Bind}"
Toggled="CalendarSynchronizationToggled" />
</controls:SettingsCard>
<controls:SettingsCard Description="{x:Bind domain:Translator.CalendarAccountSettings_DefaultShowAsDescription, Mode=OneTime}" Header="{x:Bind domain:Translator.CalendarAccountSettings_DefaultShowAs, Mode=OneTime}">
<controls:SettingsCard.HeaderIcon>
<FontIcon Glyph="&#xE163;" />
</controls:SettingsCard.HeaderIcon>
<ComboBox
ItemsSource="{x:Bind ShowAsOptions, Mode=OneWay}"
SelectedItem="{x:Bind SelectedShowAsOption, Mode=OneWay}"
SelectionChanged="CalendarShowAsSelectionChanged"
Tag="{x:Bind}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="mailViewModels:AccountCalendarShowAsOption">
<TextBlock Text="{x:Bind DisplayText}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</controls:SettingsCard>
</controls:SettingsExpander.Items>
</controls:SettingsExpander>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
@@ -1,8 +1,8 @@
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Navigation;
using Wino.Core.Domain.Entities.Calendar;
using Wino.Core.Domain.Models.Folders;
using Wino.Mail.ViewModels;
using Wino.Views.Abstract;
namespace Wino.Views;
@@ -37,11 +37,21 @@ public sealed partial class AccountDetailsPage : AccountDetailsPageAbstract
}
}
private void CalendarItemClicked(object sender, RoutedEventArgs e)
private async void CalendarSynchronizationToggled(object sender, RoutedEventArgs e)
{
if (sender is CommunityToolkit.WinUI.Controls.SettingsCard settingsCard && settingsCard.CommandParameter is AccountCalendar calendar)
if (sender is ToggleSwitch { Tag: AccountCalendarSettingsItemViewModel calendarItem } toggleSwitch)
{
ViewModel.CalendarItemClickedCommand?.Execute(calendar);
calendarItem.IsSynchronizationEnabled = toggleSwitch.IsOn;
await ViewModel.UpdateCalendarSynchronizationAsync(calendarItem.Calendar, toggleSwitch.IsOn);
}
}
private async void CalendarShowAsSelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (sender is ComboBox { Tag: AccountCalendarSettingsItemViewModel calendarItem, SelectedItem: AccountCalendarShowAsOption option })
{
calendarItem.SelectedShowAsOption = option;
await ViewModel.UpdateCalendarDefaultShowAsAsync(calendarItem.Calendar, option);
}
}
@@ -3,6 +3,7 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:abstract="using:Wino.Mail.WinUI.Views.Abstract"
xmlns:calendarViewModels="using:Wino.Calendar.ViewModels"
xmlns:controls="using:CommunityToolkit.WinUI.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:domain="using:Wino.Core.Domain"
@@ -56,16 +57,6 @@
<ToggleSwitch IsOn="{x:Bind ViewModel.IsSyncEnabled, Mode=TwoWay}" />
</controls:SettingsCard>
<!-- Primary Calendar -->
<controls:SettingsCard
Description="{x:Bind domain:Translator.CalendarAccountSettings_PrimaryCalendarDescription, Mode=OneTime}"
Header="{x:Bind domain:Translator.CalendarAccountSettings_PrimaryCalendar, Mode=OneTime}">
<controls:SettingsCard.HeaderIcon>
<FontIcon Glyph="&#xE735;" />
</controls:SettingsCard.HeaderIcon>
<ToggleSwitch IsOn="{x:Bind ViewModel.IsPrimaryCalendar, Mode=TwoWay}" />
</controls:SettingsCard>
<!-- Default Show As Status -->
<controls:SettingsCard
Description="{x:Bind domain:Translator.CalendarAccountSettings_DefaultShowAsDescription, Mode=OneTime}"
@@ -75,9 +66,14 @@
</controls:SettingsCard.HeaderIcon>
<ComboBox
MinWidth="150"
DisplayMemberPath="DisplayText"
ItemsSource="{x:Bind ViewModel.ShowAsOptions, Mode=OneWay}"
SelectedItem="{x:Bind ViewModel.SelectedDefaultShowAsOption, Mode=TwoWay}" />
SelectedItem="{x:Bind ViewModel.SelectedDefaultShowAsOption, Mode=TwoWay}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="calendarViewModels:ShowAsOption">
<TextBlock Text="{x:Bind DisplayText}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</controls:SettingsCard>
</StackPanel>
@@ -82,10 +82,10 @@
VerticalAlignment="Center"
HorizontalContentAlignment="Left"
Background="Transparent"
DisplayType="{x:Bind ViewModel.StatePersistenceService.CalendarDisplayType, Mode=OneWay}"
FontSize="14"
FontWeight="Normal"
IsHitTestVisible="False"
DisplayType="{x:Bind ViewModel.StatePersistenceService.CalendarDisplayType, Mode=OneWay}"
ItemsSource="{x:Bind ViewModel.DateNavigationHeaderItems}"
SelectedIndex="{x:Bind ViewModel.SelectedDateNavigationHeaderIndex, Mode=OneWay}">
<FlipView.ItemTemplate>
@@ -149,14 +149,37 @@
<SplitView.Pane>
<Grid Padding="0,0,0,6">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Button
Margin="10,12,10,0"
Padding="4,12"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Left"
Background="Transparent"
BorderBrush="Transparent"
Command="{x:Bind ViewModel.NewEventCommand}">
<StackPanel
HorizontalAlignment="Center"
Orientation="Horizontal"
Spacing="8">
<coreControls:WinoFontIcon FontSize="16" Icon="NewMail" />
<TextBlock
Margin="10,-2,0,0"
VerticalAlignment="Center"
FontSize="16"
Style="{StaticResource FlyoutPickerTitleTextBlockStyle}"
Text="{x:Bind domain:Translator.CalendarEventCompose_NewEventButton}" />
</StackPanel>
</Button>
<calendarControls:WinoCalendarView
x:Name="CalendarView"
Grid.Row="0"
Grid.Row="1"
Margin="0,12,0,0"
HorizontalAlignment="Center"
DateClickedCommand="{x:Bind ViewModel.DateClickedCommand}"
@@ -167,7 +190,7 @@
<!-- Account Calendars Host -->
<ListView
x:Name="CalendarHostListView"
Grid.Row="1"
Grid.Row="2"
ItemsSource="{x:Bind ViewModel.AccountCalendarStateService.GroupedAccountCalendars}"
SelectionMode="None">
<ListView.Header>
@@ -261,13 +284,16 @@
<!-- Menu Items -->
<ListView
Grid.Row="2"
Grid.Row="3"
ItemTemplateSelector="{StaticResource NavigationMenuTemplateSelector}"
SelectedIndex="{x:Bind ViewModel.SelectedMenuItemIndex, Mode=TwoWay}">
<ListView.Items>
<ListViewItem>
<StackPanel Orientation="Horizontal" Spacing="12">
<FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" FontSize="16" Glyph="&#xE77B;" />
<FontIcon
FontFamily="{StaticResource SymbolThemeFontFamily}"
FontSize="16"
Glyph="&#xE77B;" />
<TextBlock VerticalAlignment="Center" Text="{x:Bind domain:Translator.MenuManageAccounts}" />
</StackPanel>
@@ -0,0 +1,585 @@
<?xml version="1.0" encoding="utf-8" ?>
<abstract:CalendarEventComposePageAbstract
x:Class="Wino.Calendar.Views.CalendarEventComposePage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:abstract="using:Wino.Mail.WinUI.Views.Abstract"
xmlns:calendarViewModels="using:Wino.Calendar.ViewModels"
xmlns:controls="using:Wino.Controls"
xmlns:coreControls="using:Wino.Mail.WinUI.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:data="using:Wino.Calendar.ViewModels.Data"
xmlns:domain="using:Wino.Core.Domain"
xmlns:helpers="using:Wino.Helpers"
xmlns:mailControls="using:Wino.Mail.Controls"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:shared="using:Wino.Core.Domain.Entities.Shared"
xmlns:toolkit="using:CommunityToolkit.WinUI.Controls"
Style="{StaticResource PageStyle}"
mc:Ignorable="d">
<Page.Resources>
<Style
x:Key="TransparentActionButtonStyle"
BasedOn="{StaticResource DefaultButtonStyle}"
TargetType="Button">
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Padding" Value="8" />
<Setter Property="MinWidth" Value="0" />
<Setter Property="MinHeight" Value="0" />
</Style>
<Style
x:Key="FieldToggleButtonStyle"
BasedOn="{StaticResource DefaultToggleButtonStyle}"
TargetType="ToggleButton">
<Setter Property="Padding" Value="12,6" />
<Setter Property="MinWidth" Value="0" />
<Setter Property="MinHeight" Value="0" />
<Setter Property="CornerRadius" Value="4" />
</Style>
<DataTemplate x:Key="AttendeeSuggestionTemplate" x:DataType="shared:AccountContact">
<StackPanel Padding="8,4" Orientation="Vertical">
<TextBlock FontWeight="SemiBold" Text="{x:Bind Name}" />
<TextBlock FontSize="12" Text="{x:Bind Address}" />
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="AttendeeTokenTemplate" x:DataType="data:CalendarComposeAttendeeViewModel">
<TextBlock Text="{x:Bind DisplayName}" />
</DataTemplate>
</Page.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!-- Top Bar -->
<Grid
Padding="16,10"
Background="{ThemeResource WinoContentZoneBackgroud}"
CornerRadius="{StaticResource ControlCornerRadius}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<!-- Left: Save + Discard -->
<StackPanel Orientation="Horizontal" Spacing="8">
<Button Command="{x:Bind ViewModel.CreateCommand}">
<Button.Style>
<Style BasedOn="{StaticResource AccentButtonStyle}" TargetType="Button">
<Setter Property="Padding" Value="16,6" />
</Style>
</Button.Style>
<StackPanel Orientation="Horizontal" Spacing="8">
<coreControls:WinoFontIcon FontSize="16" Icon="Save" />
<TextBlock VerticalAlignment="Center" Text="{x:Bind domain:Translator.Buttons_Save}" />
</StackPanel>
</Button>
<Button Command="{x:Bind ViewModel.CancelCommand}" Style="{StaticResource TransparentActionButtonStyle}">
<StackPanel Orientation="Horizontal" Spacing="8">
<coreControls:WinoFontIcon FontSize="16" Icon="Dismiss" />
<TextBlock VerticalAlignment="Center" Text="{x:Bind domain:Translator.Buttons_Discard}" />
</StackPanel>
</Button>
</StackPanel>
<!-- Right: Calendar, Show As, Reminder -->
<StackPanel
Grid.Column="2"
Orientation="Horizontal"
Spacing="12">
<!-- Calendar -->
<StackPanel
VerticalAlignment="Center"
Orientation="Horizontal"
Spacing="8">
<coreControls:WinoFontIcon FontSize="14" Icon="Calendar" />
<Button
Padding="10,6"
HorizontalContentAlignment="Left"
Style="{StaticResource DefaultButtonStyle}">
<Button.Flyout>
<Flyout Placement="BottomEdgeAlignedLeft">
<ScrollViewer MaxHeight="360">
<ItemsControl ItemsSource="{x:Bind ViewModel.AvailableCalendarGroups, Mode=OneWay}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="data:GroupedAccountCalendarViewModel">
<StackPanel
MinWidth="320"
Padding="0,0,0,12"
Spacing="6">
<TextBlock FontWeight="SemiBold">
<Run Text="{x:Bind Account.Name}" />
<Run Text=" (" />
<Run Text="{x:Bind Account.Address}" />
<Run Text=")" />
</TextBlock>
<ListView
IsItemClickEnabled="True"
ItemClick="ComposeCalendarClicked"
ItemsSource="{x:Bind AccountCalendars}"
SelectionMode="None">
<ListView.ItemTemplate>
<DataTemplate x:DataType="data:AccountCalendarViewModel">
<Grid ColumnSpacing="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Ellipse
Width="14"
Height="14"
VerticalAlignment="Center"
Fill="{x:Bind helpers:XamlHelpers.GetSolidColorBrushFromHex(BackgroundColorHex), Mode=OneWay}" />
<TextBlock
Grid.Column="1"
VerticalAlignment="Center"
Text="{x:Bind Name}" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Flyout>
</Button.Flyout>
<StackPanel Orientation="Horizontal" Spacing="8">
<Ellipse
Width="10"
Height="10"
VerticalAlignment="Center"
Fill="{x:Bind helpers:XamlHelpers.GetSolidColorBrushFromHex(ViewModel.SelectedCalendar.BackgroundColorHex), Mode=OneWay}" />
<StackPanel Spacing="0">
<TextBlock Text="{x:Bind ViewModel.SelectedCalendarDisplayText, Mode=OneWay}" />
<TextBlock
FontSize="11"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Text="{x:Bind ViewModel.SelectedCalendarAccountText, Mode=OneWay}"
Visibility="{x:Bind helpers:XamlHelpers.StringToVisibilityConverter(ViewModel.SelectedCalendarAccountText), Mode=OneWay}" />
</StackPanel>
<FontIcon Glyph="&#xE70D;" />
</StackPanel>
</Button>
</StackPanel>
<!-- Show As -->
<StackPanel
VerticalAlignment="Center"
Orientation="Horizontal"
Spacing="8">
<coreControls:WinoFontIcon FontSize="14" Icon="CalendarShowAs" />
<ComboBox
VerticalAlignment="Center"
ItemsSource="{x:Bind ViewModel.ShowAsOptions}"
SelectedItem="{x:Bind ViewModel.SelectedShowAsOption, Mode=TwoWay}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="calendarViewModels:ShowAsOption">
<TextBlock Text="{x:Bind DisplayText}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</StackPanel>
<!-- Reminder -->
<StackPanel
VerticalAlignment="Center"
Orientation="Horizontal"
Spacing="8">
<coreControls:WinoFontIcon FontSize="14" Icon="Reminder" />
<ComboBox
VerticalAlignment="Center"
ItemsSource="{x:Bind ViewModel.ReminderOptions}"
SelectedItem="{x:Bind ViewModel.SelectedReminderOption, Mode=TwoWay}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="calendarViewModels:ReminderOption">
<TextBlock Text="{x:Bind DisplayText}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</StackPanel>
</StackPanel>
</Grid>
<!-- Scrollable Content -->
<ScrollViewer Grid.Row="1" MaxWidth="1200">
<StackPanel
Padding="40,24,40,40"
HorizontalAlignment="Stretch"
Spacing="0">
<!-- Title -->
<TextBox
FontSize="24"
PlaceholderText="{x:Bind domain:Translator.CalendarEventCompose_TitlePlaceholder}"
Text="{x:Bind ViewModel.Title, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<TextBox.Style>
<Style BasedOn="{StaticResource DefaultTextBoxStyle}" TargetType="TextBox">
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="BorderBrush" Value="Transparent" />
<!--<Setter Property="Padding" Value="0,8" />-->
</Style>
</TextBox.Style>
</TextBox>
<!-- Divider -->
<Border
Height="1"
Margin="0,0,0,20"
Background="{ThemeResource DividerStrokeColorDefaultBrush}" />
<!-- Date Row -->
<StackPanel
Margin="0,0,0,12"
Orientation="Horizontal"
Spacing="12">
<DatePicker Date="{x:Bind ViewModel.StartDate, Mode=TwoWay}" Header="{x:Bind domain:Translator.CalendarEventCompose_StartDate}" />
<ToggleButton
VerticalAlignment="Bottom"
Content="{x:Bind domain:Translator.CalendarEventCompose_AllDay}"
IsChecked="{x:Bind ViewModel.IsAllDay, Mode=TwoWay}"
Style="{StaticResource FieldToggleButtonStyle}" />
</StackPanel>
<!-- Time Row -->
<StackPanel
Margin="0,0,0,8"
Orientation="Horizontal"
Spacing="12"
Visibility="{x:Bind helpers:XamlHelpers.ReverseBoolToVisibilityConverter(ViewModel.IsAllDay), Mode=OneWay}">
<TimePicker
ClockIdentifier="{x:Bind ViewModel.TimePickerClockIdentifier, Mode=OneWay}"
Header="{x:Bind domain:Translator.CalendarEventCompose_StartTime}"
SelectedTime="{x:Bind ViewModel.StartTime, Mode=TwoWay}" />
<TextBlock
Margin="0,28,0,0"
VerticalAlignment="Center"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Text="—" />
<TimePicker
ClockIdentifier="{x:Bind ViewModel.TimePickerClockIdentifier, Mode=OneWay}"
Header="{x:Bind domain:Translator.CalendarEventCompose_EndTime}"
SelectedTime="{x:Bind ViewModel.EndTime, Mode=TwoWay}" />
</StackPanel>
<!-- All Day End Date -->
<DatePicker
Margin="0,0,0,8"
Date="{x:Bind ViewModel.AllDayEndDate, Mode=TwoWay}"
Header="{x:Bind domain:Translator.CalendarEventCompose_EndDate}"
Visibility="{x:Bind ViewModel.IsAllDay, Mode=OneWay}" />
<!-- Date/Time Summary -->
<TextBlock
Margin="0,0,0,16"
FontSize="13"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Text="{x:Bind ViewModel.RecurrenceSummary, Mode=OneWay}"
TextWrapping="Wrap" />
<!-- Location -->
<TextBox
Margin="0,0,0,12"
PlaceholderText="{x:Bind domain:Translator.CalendarEventCompose_LocationPlaceholder}"
Text="{x:Bind ViewModel.Location, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<!-- Recurring Toggle -->
<ToggleButton
Margin="0,0,0,4"
IsChecked="{x:Bind ViewModel.IsRecurring, Mode=TwoWay}"
Style="{StaticResource FieldToggleButtonStyle}">
<StackPanel Orientation="Horizontal" Spacing="8">
<coreControls:WinoFontIcon FontSize="14" Icon="CalendarEventRepeat" />
<TextBlock Text="{x:Bind domain:Translator.CalendarEventCompose_Recurring}" />
</StackPanel>
</ToggleButton>
<!-- Recurrence Panel -->
<Border
Margin="0,8,0,4"
Padding="16"
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
CornerRadius="{StaticResource ControlCornerRadius}"
Visibility="{x:Bind ViewModel.IsRecurring, Mode=OneWay}">
<StackPanel Spacing="12">
<Grid ColumnSpacing="8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock VerticalAlignment="Center" Text="{x:Bind domain:Translator.CalendarEventCompose_RepeatEvery}" />
<ComboBox
Grid.Column="1"
ItemsSource="{x:Bind ViewModel.RecurrenceIntervalOptions}"
SelectedItem="{x:Bind ViewModel.SelectedRecurrenceInterval, Mode=TwoWay}" />
<TextBlock
Grid.Column="2"
VerticalAlignment="Center"
Text="{x:Bind domain:Translator.CalendarEventCompose_Every}" />
<ComboBox
Grid.Column="3"
ItemsSource="{x:Bind ViewModel.RecurrenceFrequencyOptions}"
SelectedItem="{x:Bind ViewModel.SelectedRecurrenceFrequencyOption, Mode=TwoWay}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="calendarViewModels:CalendarComposeFrequencyOption">
<TextBlock Text="{x:Bind DisplayText}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<TextBlock
Grid.Column="4"
VerticalAlignment="Center"
Text="{x:Bind domain:Translator.CalendarEventCompose_ForWeekdays}" />
<ItemsControl Grid.Column="5" ItemsSource="{x:Bind ViewModel.WeekdayOptions}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" Spacing="4" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="calendarViewModels:CalendarComposeWeekdayOption">
<ToggleButton
Width="32"
Height="32"
Padding="0"
IsChecked="{x:Bind IsSelected, Mode=TwoWay}">
<TextBlock HorizontalAlignment="Center" Text="{x:Bind Label}" />
</ToggleButton>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<TextBlock
Grid.Column="6"
VerticalAlignment="Center"
Text="{x:Bind domain:Translator.CalendarEventCompose_Until}" />
<CalendarDatePicker
Grid.Column="7"
Date="{x:Bind ViewModel.RecurrenceEndDate, Mode=TwoWay}"
PlaceholderText="{x:Bind domain:Translator.CalendarEventCompose_NoEndDate}" />
<Button
Grid.Column="8"
Command="{x:Bind ViewModel.ClearRecurrenceEndDateCommand}"
Style="{StaticResource TransparentActionButtonStyle}">
<coreControls:WinoFontIcon FontSize="14" Icon="Dismiss" />
</Button>
</Grid>
</StackPanel>
</Border>
<!-- People & Attachments Toggle Row -->
<StackPanel
Margin="0,12,0,4"
Orientation="Horizontal"
Spacing="8">
<ToggleButton x:Name="PeopleToggle" Style="{StaticResource FieldToggleButtonStyle}">
<StackPanel Orientation="Horizontal" Spacing="8">
<coreControls:WinoFontIcon FontSize="14" Icon="People" />
<TextBlock Text="{x:Bind domain:Translator.CalendarEventDetails_People}" />
</StackPanel>
</ToggleButton>
<ToggleButton x:Name="AttachmentsToggle" Style="{StaticResource FieldToggleButtonStyle}">
<StackPanel Orientation="Horizontal" Spacing="8">
<coreControls:WinoFontIcon FontSize="14" Icon="Attachment" />
<TextBlock Text="{x:Bind domain:Translator.CalendarEventDetails_Attachments}" />
</StackPanel>
</ToggleButton>
</StackPanel>
<!-- People Pane -->
<Border
Margin="0,8,0,0"
Padding="16"
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
CornerRadius="{StaticResource ControlCornerRadius}"
Visibility="{x:Bind PeopleToggle.IsChecked, Mode=OneWay}">
<StackPanel Spacing="8">
<toolkit:TokenizingTextBox
x:Name="AttendeeBox"
BorderThickness="0"
ItemsSource="{x:Bind ViewModel.Attendees, Mode=OneWay}"
LostFocus="AddressBoxLostFocus"
PlaceholderText="{x:Bind domain:Translator.CalendarEventDetails_InviteSomeone}"
SuggestedItemTemplate="{StaticResource AttendeeSuggestionTemplate}"
TokenDelimiter=";"
TokenItemAdding="TokenItemAdding"
TokenItemTemplate="{StaticResource AttendeeTokenTemplate}" />
<ListView
Margin="-8,0,-8,-8"
ItemsSource="{x:Bind ViewModel.Attendees, Mode=OneWay}"
SelectionMode="None">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="Padding" Value="8,4" />
<Setter Property="MinHeight" Value="0" />
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate x:DataType="data:CalendarComposeAttendeeViewModel">
<Grid ColumnSpacing="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<controls:ImagePreviewControl
Width="32"
Height="32"
Address="{x:Bind Email}"
DisplayNameOverride="{x:Bind DisplayName}"
PreviewContact="{x:Bind ResolvedContact}" />
<StackPanel
Grid.Column="1"
VerticalAlignment="Center"
Spacing="1">
<TextBlock
FontSize="13"
Text="{x:Bind DisplayName}"
TextTrimming="CharacterEllipsis" />
<TextBlock
FontSize="11"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Text="{x:Bind Email}"
TextTrimming="CharacterEllipsis"
Visibility="{x:Bind HasDistinctDisplayName, Mode=OneWay}" />
</StackPanel>
<Button
Grid.Column="2"
Padding="6,4"
VerticalAlignment="Center"
Click="RemoveAttendeeClicked"
Style="{StaticResource TransparentActionButtonStyle}"
Tag="{x:Bind}">
<coreControls:WinoFontIcon FontSize="12" Icon="Delete" />
</Button>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
</Border>
<!-- Attachments Pane -->
<Border
Margin="0,8,0,0"
Padding="16"
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
CornerRadius="{StaticResource ControlCornerRadius}"
Visibility="{x:Bind AttachmentsToggle.IsChecked, Mode=OneWay}">
<StackPanel Spacing="8">
<Button
HorizontalAlignment="Left"
Command="{x:Bind ViewModel.AddAttachmentsCommand}"
Style="{StaticResource TransparentActionButtonStyle}">
<StackPanel Orientation="Horizontal" Spacing="8">
<coreControls:WinoFontIcon FontSize="14" Icon="AttachmentNew" />
<TextBlock Text="{x:Bind domain:Translator.CalendarEventCompose_AddAttachment}" />
</StackPanel>
</Button>
<ListView
Margin="-8,0,-8,-8"
ItemsSource="{x:Bind ViewModel.Attachments, Mode=OneWay}"
SelectionMode="None">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="Padding" Value="8,4" />
<Setter Property="MinHeight" Value="0" />
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate x:DataType="data:CalendarComposeAttachmentViewModel">
<Grid Height="44" ColumnSpacing="8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="32" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ContentControl
VerticalAlignment="Center"
Content="{x:Bind AttachmentType}"
ContentTemplateSelector="{StaticResource FileTypeIconSelector}" />
<StackPanel
Grid.Column="1"
VerticalAlignment="Center"
Spacing="1">
<TextBlock
FontSize="13"
Text="{x:Bind FileName}"
TextTrimming="CharacterEllipsis" />
<TextBlock
FontSize="11"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Text="{x:Bind ReadableSize}" />
</StackPanel>
<Button
Grid.Column="2"
Padding="6,4"
VerticalAlignment="Center"
Click="RemoveAttachmentClicked"
Style="{StaticResource TransparentActionButtonStyle}"
Tag="{x:Bind}">
<coreControls:WinoFontIcon FontSize="12" Icon="Delete" />
</Button>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
</Border>
<!-- Notes Header -->
<StackPanel
Margin="0,20,0,8"
Orientation="Horizontal"
Spacing="8">
<coreControls:WinoFontIcon
FontSize="14"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Icon="Draft" />
<TextBlock Style="{StaticResource BodyStrongTextBlockStyle}" Text="{x:Bind domain:Translator.CalendarEventCompose_Notes}" />
</StackPanel>
<!-- Notes Editor -->
<mailControls:WebViewEditorControl
x:Name="NotesEditor"
MinHeight="600"
IsEditorDarkMode="{x:Bind ViewModel.IsDarkWebviewRenderer, Mode=OneWay}"
IsEditorWebViewEditor="True" />
</StackPanel>
</ScrollViewer>
</Grid>
</abstract:CalendarEventComposePageAbstract>
@@ -0,0 +1,165 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
using System.Threading;
using CommunityToolkit.Mvvm.Messaging;
using CommunityToolkit.WinUI.Controls;
using EmailValidation;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Navigation;
using Windows.Foundation;
using Wino.Messaging.Client.Shell;
using Wino.Calendar.ViewModels.Data;
using Wino.Mail.WinUI.Views.Abstract;
namespace Wino.Calendar.Views;
public sealed partial class CalendarEventComposePage : CalendarEventComposePageAbstract,
IRecipient<ApplicationThemeChanged>
{
private readonly List<IDisposable> _disposables = [];
public CalendarEventComposePage()
{
InitializeComponent();
}
protected override async void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
_disposables.Add(GetSuggestionBoxDisposable(AttendeeBox));
_disposables.Add(NotesEditor);
ViewModel.GetHtmlNotesAsync = async () => await NotesEditor.GetHtmlBodyAsync() ?? string.Empty;
await NotesEditor.RenderHtmlAsync(" ");
}
protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
{
base.OnNavigatingFrom(e);
foreach (var disposable in _disposables)
{
disposable.Dispose();
}
_disposables.Clear();
}
private IDisposable GetSuggestionBoxDisposable(TokenizingTextBox box)
{
return Observable.FromEventPattern<TypedEventHandler<AutoSuggestBox, AutoSuggestBoxTextChangedEventArgs>, AutoSuggestBoxTextChangedEventArgs>(
handler => box.TextChanged += handler,
handler => box.TextChanged -= handler)
.Throttle(TimeSpan.FromMilliseconds(120))
.ObserveOn(SynchronizationContext.Current!)
.Subscribe(async eventPattern =>
{
if (eventPattern.EventArgs.Reason != AutoSuggestionBoxTextChangeReason.UserInput)
return;
if (eventPattern.Sender is not AutoSuggestBox senderBox || senderBox.Text.Length < 2)
return;
var addresses = await ViewModel.SearchContactsAsync(senderBox.Text).ConfigureAwait(false);
await ViewModel.ExecuteUIThread(() => senderBox.ItemsSource = addresses);
});
}
private async void TokenItemAdding(TokenizingTextBox sender, TokenItemAddingEventArgs args)
{
if (!EmailValidator.Validate(args.TokenText))
{
args.Cancel = true;
ViewModel.NotifyInvalidEmail(args.TokenText);
return;
}
var deferral = args.GetDeferral();
try
{
var attendee = await ViewModel.GetAttendeeAsync(args.TokenText);
if (attendee == null)
{
args.Cancel = true;
ViewModel.NotifyAddressExists();
return;
}
args.Item = attendee;
}
finally
{
deferral.Complete();
}
}
private async void AddressBoxLostFocus(object sender, RoutedEventArgs e)
{
if (sender is not TokenizingTextBox tokenizingTextBox)
return;
if (tokenizingTextBox.Items.LastOrDefault() is not ITokenStringContainer info)
return;
var currentText = info.Text;
if (string.IsNullOrWhiteSpace(currentText) || !EmailValidator.Validate(currentText))
return;
var attendee = await ViewModel.GetAttendeeAsync(currentText);
if (attendee == null)
{
tokenizingTextBox.Text = string.Empty;
return;
}
ViewModel.AddAttendee(attendee);
tokenizingTextBox.Text = string.Empty;
}
private void RemoveAttendeeClicked(object sender, RoutedEventArgs e)
{
if (sender is Button { Tag: CalendarComposeAttendeeViewModel attendee })
{
ViewModel.RemoveAttendeeCommand.Execute(attendee);
}
}
private void RemoveAttachmentClicked(object sender, RoutedEventArgs e)
{
if (sender is Button { Tag: CalendarComposeAttachmentViewModel attachment })
{
ViewModel.RemoveAttachmentCommand.Execute(attachment);
}
}
private void ComposeCalendarClicked(object sender, ItemClickEventArgs e)
{
if (e.ClickedItem is AccountCalendarViewModel calendar)
{
ViewModel.SelectedCalendar = calendar;
}
}
public void Receive(ApplicationThemeChanged message)
{
ViewModel.IsDarkWebviewRenderer = message.IsUnderlyingThemeDark;
NotesEditor.IsEditorDarkMode = message.IsUnderlyingThemeDark;
}
protected override void RegisterRecipients()
{
base.RegisterRecipients();
WeakReferenceMessenger.Default.Register<ApplicationThemeChanged>(this);
}
protected override void UnregisterRecipients()
{
base.UnregisterRecipients();
WeakReferenceMessenger.Default.Unregister<ApplicationThemeChanged>(this);
}
}
@@ -3,9 +3,11 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:abstract="using:Wino.Mail.WinUI.Views.Abstract"
xmlns:calendarViewModels="using:Wino.Calendar.ViewModels"
xmlns:controls="using:CommunityToolkit.WinUI.Controls"
xmlns:controls1="using:Microsoft.UI.Xaml.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:data="using:Wino.Calendar.ViewModels.Data"
xmlns:domain="using:Wino.Core.Domain"
xmlns:entities="using:Wino.Core.Domain.Entities.Shared"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
@@ -236,9 +238,7 @@
</controls:SettingsCard.Content>
</controls:SettingsCard>
<controls:SettingsCard
Description="{x:Bind domain:Translator.CalendarSettings_DefaultSnoozeDuration_Description}"
Header="{x:Bind domain:Translator.CalendarSettings_DefaultSnoozeDuration_Header}">
<controls:SettingsCard Description="{x:Bind domain:Translator.CalendarSettings_DefaultSnoozeDuration_Description}" Header="{x:Bind domain:Translator.CalendarSettings_DefaultSnoozeDuration_Header}">
<controls:SettingsCard.HeaderIcon>
<PathIcon Data="F1 M 10 1.25 C 10.456706 1.25 10.889486 1.337565 11.298339 1.512695 C 11.707192 1.687826 12.072591 1.927409 12.394531 2.231445 C 12.716471 2.535482 12.97656 2.892253 13.173828 3.301758 C 13.371096 3.711263 13.481771 4.146484 13.505859 4.607422 L 13.505859 5 C 13.969401 5.028646 14.386068 5.16276 14.755859 5.402344 C 15.125651 5.641927 15.414713 5.947917 15.623047 6.320312 C 15.83138 6.692709 15.9349 7.096355 15.933594 7.53125 L 15.933594 8.75 L 16.25 8.75 C 16.822917 8.75 17.317057 8.95638 17.732422 9.369141 C 18.147787 9.781901 18.357422 10.273437 18.359375 10.84375 L 18.359375 16.40625 C 18.359375 16.979167 18.153971 17.473308 17.743164 17.888672 C 17.332357 18.304037 16.839844 18.511719 16.265625 18.511719 L 3.734375 18.511719 C 3.164062 18.511719 2.671549 18.304037 2.256836 17.888672 C 1.842122 17.473308 1.634114 16.979167 1.630859 16.40625 L 1.630859 10.84375 C 1.630859 10.273437 1.837565 9.781901 2.250977 9.369141 C 2.664388 8.95638 3.156901 8.75 3.728516 8.75 L 4.0625 8.75 L 4.0625 7.53125 C 4.0625 7.09375 4.166341 6.689453 4.374023 6.314453 C 4.581706 5.939453 4.86914 5.632486 5.236328 5.393555 C 5.603516 5.154623 6.019532 5.021485 6.484375 4.994141 L 6.484375 4.607422 C 6.506511 4.148438 6.617838 3.714518 6.818359 3.305664 C 7.01888 2.896811 7.282877 2.539063 7.610352 2.232422 C 7.937826 1.92578 8.308268 1.685222 8.721679 1.510742 C 9.135091 1.336264 9.56575 1.249024 10.013672 1.249024 Z M 10.013672 2.5 C 9.441406 2.5 8.947916 2.706381 8.533203 3.119141 C 8.118489 3.531901 7.911459 4.023437 7.912109 4.59375 L 7.912109 6.25 L 12.089844 6.25 L 12.089844 4.59375 C 12.089844 4.023438 11.882161 3.531902 11.466797 3.119141 C 11.051433 2.706382 10.557292 2.5 9.984375 2.5 Z M 5.3125 7.53125 L 5.3125 8.75 L 14.6875 8.75 L 14.6875 7.53125 C 14.6875 7.303385 14.605144 7.107747 14.440429 6.944336 C 14.275714 6.780925 14.080729 6.69987 13.855469 6.703125 L 6.142578 6.703125 C 5.914713 6.703125 5.71875 6.785482 5.552734 6.950195 C 5.386719 7.114909 5.30339 7.310547 5.300781 7.537109 Z M 16.25 10 L 3.75 10 C 3.540365 10 3.361328 10.071615 3.212891 10.214844 C 3.064453 10.358073 2.989258 10.534505 2.986328 10.744141 L 2.986328 16.40625 C 2.986328 16.618489 3.058595 16.797526 3.203125 16.943359 C 3.347656 17.089193 3.526693 17.161458 3.740234 17.15625 L 16.25 17.15625 C 16.458333 17.15625 16.636067 17.082683 16.783203 16.935547 C 16.930339 16.788411 17.003906 16.609375 17.003906 16.398437 L 17.003906 10.742187 C 17.003906 10.536459 16.932942 10.359049 16.791016 10.209961 C 16.64909 10.060873 16.469401 9.986328 16.257812 9.986328 Z M 10 11.5625 C 10.227865 11.5625 10.423502 11.644856 10.586914 11.809571 C 10.750325 11.974285 10.83138 12.16862 10.830078 12.393555 L 10.830078 13.427734 L 11.855469 13.427734 C 12.080404 13.427734 12.273437 13.509115 12.434571 13.671875 C 12.595704 13.834636 12.675781 14.026693 12.675781 14.248047 C 12.675781 14.46224 12.596354 14.653321 12.4375 14.813477 C 12.278646 14.973633 12.089192 15.053711 11.869141 15.053711 L 10.830078 15.053711 L 10.830078 16.074219 C 10.830078 16.296224 10.748372 16.486981 10.584961 16.646484 C 10.42155 16.805989 10.229818 16.885742 10.005859 16.885742 C 9.781901 16.885742 9.590495 16.806315 9.431641 16.647461 C 9.272786 16.488607 9.193359 16.296875 9.193359 16.072266 L 9.193359 15.053711 L 8.15625 15.053711 C 7.931314 15.053711 7.738934 14.972331 7.579102 14.80957 C 7.419269 14.646809 7.339192 14.454753 7.338867 14.233399 C 7.338867 14.008464 7.419921 13.815755 7.582031 13.655274 C 7.744141 13.494793 7.935872 13.414551 8.157227 13.414551 L 9.193359 13.414551 L 9.193359 12.394531 C 9.193359 12.166667 9.275715 11.971029 9.440429 11.807618 C 9.605144 11.644206 9.799479 11.562825 10.023437 11.5625 Z" />
</controls:SettingsCard.HeaderIcon>
@@ -246,6 +246,40 @@
<ComboBox ItemsSource="{x:Bind ViewModel.SnoozeOptions, Mode=OneWay}" SelectedIndex="{x:Bind ViewModel.SelectedDefaultSnoozeIndex, Mode=TwoWay}" />
</controls:SettingsCard.Content>
</controls:SettingsCard>
<controls:SettingsCard Description="{x:Bind domain:Translator.CalendarSettings_NewEventBehavior_Description}" Header="{x:Bind domain:Translator.CalendarSettings_NewEventBehavior_Header}">
<controls:SettingsCard.HeaderIcon>
<FontIcon Glyph="&#xE163;" />
</controls:SettingsCard.HeaderIcon>
<controls:SettingsCard.Content>
<StackPanel Spacing="12">
<ComboBox ItemsSource="{x:Bind ViewModel.NewEventBehaviorOptions, Mode=OneWay}" SelectedItem="{x:Bind ViewModel.SelectedNewEventBehaviorOption, Mode=TwoWay}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="calendarViewModels:CalendarNewEventBehaviorOption">
<TextBlock Text="{x:Bind DisplayText}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<ComboBox
ItemsSource="{x:Bind ViewModel.AvailableNewEventCalendars, Mode=OneWay}"
SelectedItem="{x:Bind ViewModel.SelectedNewEventCalendar, Mode=TwoWay}"
Visibility="{x:Bind ViewModel.ShouldShowSpecificNewEventCalendar, Mode=OneWay}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="data:AccountCalendarViewModel">
<StackPanel Orientation="Vertical" Spacing="2">
<TextBlock Text="{x:Bind Name}" />
<TextBlock
FontSize="12"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Text="{x:Bind Account.Address}" />
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</StackPanel>
</controls:SettingsCard.Content>
</controls:SettingsCard>
</StackPanel>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="ClockIdentifierStates">
@@ -179,9 +179,14 @@
<ComboBox
Width="150"
VerticalAlignment="Center"
DisplayMemberPath="DisplayText"
ItemsSource="{x:Bind ViewModel.ShowAsOptions}"
SelectedItem="{x:Bind ViewModel.SelectedShowAsOption, Mode=TwoWay}" />
SelectedItem="{x:Bind ViewModel.SelectedShowAsOption, Mode=TwoWay}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="calendarViewModels:ShowAsOption">
<TextBlock Text="{x:Bind DisplayText}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</StackPanel>
<!-- Reminder -->