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 { private readonly List _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, 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(this); } protected override void UnregisterRecipients() { base.UnregisterRecipients(); WeakReferenceMessenger.Default.Unregister(this); } }