# Copilot Instructions for Wino-Mail Project ## Project Overview Wino Mail is a native Windows mail client targeting Windows 10 1809+ and Windows 11. The project is **transitioning from UWP to WinUI 3** - always work with WinUI projects (Wino.Mail.WinUI, Wino.Core.WinUI), never edit the old Wino.Mail UWP project. ### Key Technologies - **WinUI 3** for UI (previously UWP/WinUI 2) - **MVVM Toolkit** (CommunityToolkit.Mvvm) for ViewModels with source generators - **Messenger** pattern (WeakReferenceMessenger.Default) for event pub-sub throughout the codebase - **SQLite** database stored in publisher cache folder (not local storage) - **WebView2** for mail rendering/composition with custom HTML/JavaScript editors - **MimeKit/MailKit** for IMAP/SMTP operations - **Microsoft Graph SDK** for Outlook synchronization - **Gmail API** for Gmail synchronization ### Solution Structure ``` Wino.Core.Domain → Entities, interfaces, translations, enums (shared contracts) Wino.Core → Synchronization engine, authenticators, request processing Wino.Services → Database, mail, folder, account services Wino.Mail.ViewModels → Mail-specific ViewModels Wino.Core.ViewModels → Shared ViewModels (settings, personalization) Wino.Mail.WinUI → **Active WinUI 3 UI project** (use this) Wino.Mail → **Deprecated UWP project** (DO NOT EDIT) ``` ## Architecture Patterns ### Mail Synchronization Flow 1. **WinoRequestDelegator** → Validates and delegates user actions (mark read, delete, move) 2. **WinoRequestProcessor** → Batches requests using RequestComparer, queues to synchronizers 3. **Synchronizers** (OutlookSynchronizer, GmailSynchronizer, ImapSynchronizer) → Execute batched operations 4. **ChangeProcessors** (OutlookChangeProcessor, etc.) → Apply changes to local database 5. Database updates trigger **Messenger** events (MailAddedMessage, MailUpdatedMessage, etc.) ### Queue-Based Sync (New Pattern - See QUEUE_SYNC_IMPLEMENTATION.md) - Initial sync now queues mail IDs first (MailItemQueue table), downloads metadata only (no MIME) - MIME content downloaded on-demand when user opens mail - Synchronizers override `QueueMailIdsForInitialSyncAsync()`, `DownloadMailsFromQueueAsync()`, `CreateMinimalMailCopyAsync()` - Check `MailItemFolder.IsInitialSyncCompleted` to determine sync state ### Dependency Injection Setup Services registered in extension methods across projects: - `RegisterCoreServices()` in Wino.Core/CoreContainerSetup.cs - `RegisterSharedServices()` in Wino.Services/ServicesContainerSetup.cs - `RegisterCoreUWPServices()` in CoreUWPContainerSetup.cs - ViewModels registered in App.xaml.cs with AddTransient/AddSingleton ### Messenger Pattern (Event Pub-Sub) - All ViewModels inherit from CoreBaseViewModel or MailBaseViewModel which implement IRecipient - Register/unregister message handlers in `RegisterRecipients()` / `UnregisterRecipients()` - Send messages via `WeakReferenceMessenger.Default.Send(new MessageType(...))` - Common messages: MailAddedMessage, MailUpdatedMessage, NavigationRequested, ThemeChanged ## ViewModels Development Guidelines ### Observable Properties - Critical Pattern - **ALWAYS** use `public partial` observable properties with MVVM Toolkit source generators - **NEVER** use private fields with `[ObservableProperty]` attribute - **Correct:** ```csharp [ObservableProperty] public partial string SearchQuery { get; set; } = string.Empty; ``` - **Incorrect:** ```csharp [ObservableProperty] private string searchQuery = string.Empty; // WRONG - will not work ``` ### ViewModels Structure - Inherit from MailBaseViewModel (for mail features) or CoreBaseViewModel (for shared features) - Use `[RelayCommand]` for command methods - source generator creates Command properties - Implement IRecipient for message handlers - Use `IMailDialogService` for Mail-related dialogs, `IDialogServiceBase` for core dialogs - Call `RegisterRecipients()` in constructor/OnNavigatedTo, `UnregisterRecipients()` in OnNavigatedFrom ## Localization System ### Translation Workflow (Custom T4-based System) 1. Add English strings ONLY to `Wino.Core.Domain/Translations/en_US/resources.json` 2. Build the project - source generators automatically create Translator properties 3. Use `Translator.{PropertyName}` in ViewModels, XAML (with x:Bind, OneTime mode) 4. **NEVER** edit other language files - Crowdin manages translations automatically 5. **NEVER** hardcode user-facing strings ### Usage Examples ```csharp // ViewModel _dialogService.InfoBarMessage(Translator.Info_MissingFolderTitle, message); // XAML ``` ## UI Data Binding and Converters ### WinUI 3 Automatic Conversions - **NEVER** create IValueConverter classes or add them to Converters.xaml - **NEVER** use BoolToVisibilityConverter - WinUI 3 SDK automatically converts bool to Visibility - Direct binding: `Visibility="{x:Bind IsVisible, Mode=OneWay}"` - Register control events (for example `Loaded`, `Unloaded`, `SizeChanged`, `PointerEntered`) in XAML markup, not with `+=` in `.xaml.cs`. ### XamlHelpers for Complex Conversions - **ALWAYS** use XamlHelpers static methods instead of converters - Add xmlns: `xmlns:helpers="using:Wino.Helpers"` - Usage: `{x:Bind helpers:XamlHelpers.ReverseBoolToVisibilityConverter(PropertyName), Mode=OneWay}` - Available methods: ReverseBoolToVisibilityConverter, CountToBooleanConverter, BoolToSelectionMode, Base64ToBitmapImage - Add new methods to XamlHelpers.cs when needed, don't create converters ## WebView2 Mail Rendering ### Architecture - **reader.html** (Wino.Mail.WinUI/JS/) for reading mails - **editor.html** for composing mails (uses Jodit editor, not Quill as originally planned) - WebView2 uses virtual host mapping: `https://wino.mail/reader.html` - JavaScript interop via `ExecuteScriptFunctionAsync()` to call functions like `RenderHTML()` - MIME content downloaded on-demand, not during sync ### Key Patterns - Set environment variables for WebView2 before initialization (overlay scrollbars, cache) - Wait for DOMContentLoaded event before script execution - Handle theme changes by updating editor CSS dynamically - Cancel external navigation, open in browser via Launcher.LaunchUriAsync() ## File Structure and Project Organization ### Critical Rules - **NEVER** edit files in Wino.Mail (UWP) project - it's deprecated - **ALWAYS** work with Wino.Mail.WinUI for UI components - Place ViewModels in Wino.Mail.ViewModels (mail-specific) or Wino.Core.ViewModels (shared) - Create abstract base classes in Views/Abstract folders - Mail-specific dialog services go in Wino.Mail.WinUI/Services ### Database and Storage - SQLite database in publisher cache folder (not app local storage) - EML files stored in app local storage, referenced by MailCopy.FileId - Paths resolved via MimeFileService.GetMimeMessagePath() - Database entities in Wino.Core.Domain/Entities ## Error Handling and User Feedback ### Exception Handling Patterns ```csharp try { await operation(); } catch (UnavailableSpecialFolderException ex) { _dialogService.InfoBarMessage(title, message, InfoBarMessageType.Warning, buttonText, action); } catch (NotImplementedException) { _dialogService.ShowNotSupportedMessage(); } ``` ### Dialog Service Methods - `InfoBarMessage()` - simple notifications with optional action button - `ShowConfirmationDialogAsync()` - yes/no dialogs - `PickFilesAsync()` - file selection - Always check for null/empty results from dialog operations ## Code Style and Best Practices - Use `var` where type is obvious from right side - String interpolation over string.Format for simple cases - Keep methods focused and single-responsibility - Add XML documentation for public APIs - Avoid introducing new NuGet packages - maximize use of existing libraries - Wrap async operations in try-catch blocks - Log errors via IWinoLogger but don't expose technical details to users ## Development Workflow ### Building and Running - Open WinoMail.slnx in Visual Studio 2022+ - Target platforms: x86, x64, ARM64 (ARM32 being phased out) - Minimum: Windows 10 1809, Target: Windows 11 22H2 - Set Wino.Mail.WinUI as startup project ### Testing - Test suite in Wino.Core.Tests - Manual testing required for UI/WebView2 interactions - Test synchronization with real accounts when modifying synchronizers ### Common Pitfalls - Forgetting to register ViewModels in App.xaml.cs RegisterViewModels() - Not calling RegisterRecipients() for message handlers - Using private fields with [ObservableProperty] (won't work - must be public partial) - Creating IValueConverter classes instead of using XamlHelpers - Editing UWP project files instead of WinUI equivalents - Hardcoding strings instead of using Translator - Forgetting to unregister Messenger recipients (memory leaks)