From f6932993044e2be137df71d78827d7fb1240743a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Burak=20Kaan=20K=C3=B6se?= Date: Tue, 7 Apr 2026 00:02:36 +0200 Subject: [PATCH] Get rid of system.drawing and uwp notifications pacakge. Remove the AOT/trim stuff for now. --- Directory.Packages.props | 29 ++- Wino.Core.Tests/CalendarPageViewModelTests.cs | 1 + Wino.Core/Misc/ColorHelpers.cs | 33 ++-- Wino.Mail.WinUI/App.xaml | 2 +- Wino.Mail.WinUI/App.xaml.cs | 3 +- Wino.Mail.WinUI/Controls/AiActionsPanel.xaml | 42 ++--- .../Controls/OperationCommandBar.cs | 94 +++++----- Wino.Mail.WinUI/Dialogs/PrintDialog.xaml.cs | 12 +- .../Helpers/CalendarXamlHelpers.cs | 4 +- .../Helpers/InstalledPrinterHelper.cs | 74 ++++++++ Wino.Mail.WinUI/NotificationArguments.cs | 55 ++++++ Wino.Mail.WinUI/Package.appxmanifest | 2 +- Wino.Mail.WinUI/Program.cs | 3 +- .../Services/NotificationBuilder.cs | 176 +++++++----------- .../Styles/OperationCommandBar.xaml | 37 ++-- .../Styles/OperationCommandBar.xaml.cs | 11 ++ Wino.Mail.WinUI/Views/WinoAppShell.xaml | 6 +- Wino.Mail.WinUI/Wino.Mail.WinUI.csproj | 21 --- Wino.Services/AccountService.cs | 34 +++- Wino.Services/CalDavClient.cs | 85 +++++---- 20 files changed, 422 insertions(+), 302 deletions(-) create mode 100644 Wino.Mail.WinUI/Helpers/InstalledPrinterHelper.cs create mode 100644 Wino.Mail.WinUI/NotificationArguments.cs create mode 100644 Wino.Mail.WinUI/Styles/OperationCommandBar.xaml.cs diff --git a/Directory.Packages.props b/Directory.Packages.props index e0dee889..d824c2f3 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -16,25 +16,24 @@ - - + - - + + - + - - + + - + @@ -52,21 +51,21 @@ - + - - + + - - + + @@ -74,7 +73,7 @@ - + - \ No newline at end of file + diff --git a/Wino.Core.Tests/CalendarPageViewModelTests.cs b/Wino.Core.Tests/CalendarPageViewModelTests.cs index 95239be5..021eb16e 100644 --- a/Wino.Core.Tests/CalendarPageViewModelTests.cs +++ b/Wino.Core.Tests/CalendarPageViewModelTests.cs @@ -282,6 +282,7 @@ public class CalendarPageViewModelTests public IEnumerable ActiveCalendars => _activeCalendars; public IEnumerable AllCalendars => _calendars; + public bool IsAnySynchronizationInProgress => false; public ReadOnlyObservableGroupedCollection GroupedCalendars { get; set; } = null!; public void AddGroupedAccountCalendar(GroupedAccountCalendarViewModel groupedAccountCalendar) => _groupedCalendars.Add(groupedAccountCalendar); diff --git a/Wino.Core/Misc/ColorHelpers.cs b/Wino.Core/Misc/ColorHelpers.cs index 8b012431..c6ae4450 100644 --- a/Wino.Core/Misc/ColorHelpers.cs +++ b/Wino.Core/Misc/ColorHelpers.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Drawing; using System.Globalization; using System.Linq; using Wino.Core.Domain.Misc; @@ -46,25 +45,21 @@ public static class ColorHelpers return "#FFFFFF"; } - var color = ColorTranslator.FromHtml(normalizedColor); - var luminance = ((0.299 * color.R) + (0.587 * color.G) + (0.114 * color.B)) / 255d; + var (red, green, blue) = ParseRgb(normalizedColor); + var luminance = ((0.299 * red) + (0.587 * green) + (0.114 * blue)) / 255d; return luminance > 0.6 ? "#111111" : "#FFFFFF"; } - public static string ToHexString(this Color c) => $"#{c.R:X2}{c.G:X2}{c.B:X2}"; - - public static string ToRgbString(this Color c) => $"RGB({c.R}, {c.G}, {c.B})"; private static string AdjustColor(string hexColor, int cycle) { - var color = ColorTranslator.FromHtml(hexColor); + var (red, green, blue) = ParseRgb(hexColor); var factor = Math.Max(0.55, 1.0 - (cycle * 0.08)); - var adjusted = Color.FromArgb( - (int)Math.Clamp(color.R * factor, 0, 255), - (int)Math.Clamp(color.G * factor, 0, 255), - (int)Math.Clamp(color.B * factor, 0, 255)); + var adjustedRed = (int)Math.Clamp(red * factor, 0, 255); + var adjustedGreen = (int)Math.Clamp(green * factor, 0, 255); + var adjustedBlue = (int)Math.Clamp(blue * factor, 0, 255); - return adjusted.ToHexString(); + return $"#{adjustedRed:X2}{adjustedGreen:X2}{adjustedBlue:X2}"; } private static bool TryNormalizeHexColor(string value, out string normalized) @@ -97,4 +92,18 @@ public static class ColorHelpers private static string NormalizeHexColor(string value) => TryNormalizeHexColor(value, out var normalized) ? normalized : string.Empty; + + private static (int Red, int Green, int Blue) ParseRgb(string hexColor) + { + var normalized = NormalizeHexColor(hexColor); + if (string.IsNullOrWhiteSpace(normalized)) + { + return (255, 255, 255); + } + + return ( + Convert.ToInt32(normalized.Substring(1, 2), 16), + Convert.ToInt32(normalized.Substring(3, 2), 16), + Convert.ToInt32(normalized.Substring(5, 2), 16)); + } } diff --git a/Wino.Mail.WinUI/App.xaml b/Wino.Mail.WinUI/App.xaml index 21d04fe6..066caab5 100644 --- a/Wino.Mail.WinUI/App.xaml +++ b/Wino.Mail.WinUI/App.xaml @@ -19,7 +19,7 @@ - + diff --git a/Wino.Mail.WinUI/App.xaml.cs b/Wino.Mail.WinUI/App.xaml.cs index a9391263..35ed1f86 100644 --- a/Wino.Mail.WinUI/App.xaml.cs +++ b/Wino.Mail.WinUI/App.xaml.cs @@ -8,7 +8,6 @@ using System.Threading; using System.Threading.Tasks; using CommunityToolkit.Mvvm.Messaging; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Toolkit.Uwp.Notifications; using Microsoft.UI.Dispatching; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Media.Animation; @@ -492,7 +491,7 @@ public partial class App : WinoApplication, /// private async Task HandleToastActivationAsync(AppNotificationActivatedEventArgs toastArgs) { - var toastArguments = ToastArguments.Parse(toastArgs.Argument); + var toastArguments = NotificationArguments.Parse(toastArgs.Argument); if (toastArguments.TryGetValue(Constants.ToastStoreUpdateActionKey, out string storeUpdateAction) && storeUpdateAction == Constants.ToastStoreUpdateActionInstall) diff --git a/Wino.Mail.WinUI/Controls/AiActionsPanel.xaml b/Wino.Mail.WinUI/Controls/AiActionsPanel.xaml index cf49e1f9..dafe36a9 100644 --- a/Wino.Mail.WinUI/Controls/AiActionsPanel.xaml +++ b/Wino.Mail.WinUI/Controls/AiActionsPanel.xaml @@ -34,7 +34,7 @@ + Text="{x:Bind domain:Translator.AiActions_CheckingStatus}" /> @@ -77,12 +77,12 @@ @@ -95,12 +95,12 @@ @@ -567,8 +567,8 @@ diff --git a/Wino.Mail.WinUI/Wino.Mail.WinUI.csproj b/Wino.Mail.WinUI/Wino.Mail.WinUI.csproj index 87965fa0..b9174fd9 100644 --- a/Wino.Mail.WinUI/Wino.Mail.WinUI.csproj +++ b/Wino.Mail.WinUI/Wino.Mail.WinUI.csproj @@ -12,30 +12,11 @@ true true enable - - - False - True - True - $(NoWarn);CS8305 - true - False - True - - - False - True - $(DefineConstants);DISABLE_XAML_GENERATED_MAIN - - - - - @@ -203,7 +184,6 @@ - @@ -215,7 +195,6 @@ - diff --git a/Wino.Services/AccountService.cs b/Wino.Services/AccountService.cs index 8ae13070..142c2bd1 100644 --- a/Wino.Services/AccountService.cs +++ b/Wino.Services/AccountService.cs @@ -1,6 +1,6 @@ using System; using System.Collections.Generic; -using System.Drawing; +using System.Globalization; using System.Linq; using System.Threading.Tasks; using CommunityToolkit.Diagnostics; @@ -662,14 +662,40 @@ public class AccountService : BaseDatabaseService, IAccountService private static string GetReadableTextColorHex(string backgroundColorHex) { - if (string.IsNullOrWhiteSpace(backgroundColorHex)) + if (!TryParseHexColor(backgroundColorHex, out var red, out var green, out var blue)) return "#FFFFFF"; - var color = ColorTranslator.FromHtml(backgroundColorHex); - var luminance = ((0.299 * color.R) + (0.587 * color.G) + (0.114 * color.B)) / 255d; + var luminance = ((0.299 * red) + (0.587 * green) + (0.114 * blue)) / 255d; return luminance > 0.6 ? "#111111" : "#FFFFFF"; } + private static bool TryParseHexColor(string value, out int red, out int green, out int blue) + { + red = 255; + green = 255; + blue = 255; + + if (string.IsNullOrWhiteSpace(value)) + return false; + + var color = value.Trim(); + if (color.StartsWith('#')) + { + color = color[1..]; + } + + if (color.Length != 6 || + !int.TryParse(color, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out _)) + { + return false; + } + + red = Convert.ToInt32(color.Substring(0, 2), 16); + green = Convert.ToInt32(color.Substring(2, 2), 16); + blue = Convert.ToInt32(color.Substring(4, 2), 16); + return true; + } + public async Task UpdateAccountOrdersAsync(Dictionary accountIdOrderPair) { foreach (var pair in accountIdOrderPair) diff --git a/Wino.Services/CalDavClient.cs b/Wino.Services/CalDavClient.cs index 5d110c8b..285a7145 100644 --- a/Wino.Services/CalDavClient.cs +++ b/Wino.Services/CalDavClient.cs @@ -421,14 +421,14 @@ public sealed class CalDavClient : ICalDavClient var result = new List(); var masters = allEvents - .Where(e => e != null && !string.IsNullOrWhiteSpace(e.Uid) && e.RecurrenceId == null) + .Where(e => e != null && !string.IsNullOrWhiteSpace(e.Uid) && GetRecurrenceId(e) == null) .GroupBy(e => e.Uid, StringComparer.OrdinalIgnoreCase) .Select(g => g.First()) .ToList(); var exceptionMap = allEvents - .Where(e => e != null && !string.IsNullOrWhiteSpace(e.Uid) && e.RecurrenceId != null) - .GroupBy(e => $"{e.Uid}|{GetOccurrenceKey(e.RecurrenceId)}", StringComparer.OrdinalIgnoreCase) + .Where(e => e != null && !string.IsNullOrWhiteSpace(e.Uid) && GetRecurrenceId(e) != null) + .GroupBy(e => $"{e.Uid}|{GetOccurrenceKey(GetRecurrenceId(e))}", StringComparer.OrdinalIgnoreCase) .ToDictionary(g => g.Key, g => g.First(), StringComparer.OrdinalIgnoreCase); var consumedExceptions = new HashSet(StringComparer.OrdinalIgnoreCase); @@ -453,7 +453,15 @@ public sealed class CalDavClient : ICalDavClient seriesMasterRemoteEventId: string.Empty, recurrence: BuildRecurrenceString(master))); - var occurrences = master.GetOccurrences(windowStartUtc.UtcDateTime, windowEndUtc.UtcDateTime); + var occurrences = master + .GetOccurrences( + new CalDateTime(windowStartUtc.UtcDateTime, true), + new Ical.Net.Evaluation.EvaluationOptions()) + .Where(o => Overlaps( + ToDateTimeOffset(o.Period.StartTime), + ToDateTimeOffset(o.Period.EndTime), + windowStartUtc, + windowEndUtc)); foreach (var occurrence in occurrences) { @@ -507,9 +515,10 @@ public sealed class CalDavClient : ICalDavClient } } - foreach (var exceptionEvent in allEvents.Where(e => e != null && e.RecurrenceId != null && !string.IsNullOrWhiteSpace(e.Uid))) + foreach (var exceptionEvent in allEvents.Where(e => e != null && GetRecurrenceId(e) != null && !string.IsNullOrWhiteSpace(e.Uid))) { - var key = $"{exceptionEvent.Uid}|{GetOccurrenceKey(exceptionEvent.RecurrenceId)}"; + var recurrenceId = GetRecurrenceId(exceptionEvent); + var key = $"{exceptionEvent.Uid}|{GetOccurrenceKey(recurrenceId)}"; if (consumedExceptions.Contains(key)) continue; @@ -525,7 +534,7 @@ public sealed class CalDavClient : ICalDavClient sourceEvent: exceptionEvent, start: start, end: end, - remoteEventId: BuildRemoteEventId(exceptionEvent.Uid, GetOccurrenceKey(exceptionEvent.RecurrenceId)), + remoteEventId: BuildRemoteEventId(exceptionEvent.Uid, GetOccurrenceKey(recurrenceId)), resourceHref: resourceHref, eTag: eTag, icsContent: icsContent, @@ -546,16 +555,30 @@ public sealed class CalDavClient : ICalDavClient private static bool HasRecurrence(CalendarEvent calendarEvent) => (calendarEvent.RecurrenceRules?.Any() ?? false) - || (calendarEvent.RecurrenceDates?.Any() ?? false); + || (calendarEvent.RecurrenceDates?.GetAllPeriods().Any() ?? false); private static string BuildRemoteEventId(string uid, string occurrenceKey) => string.IsNullOrWhiteSpace(occurrenceKey) ? uid : $"{uid}::{occurrenceKey}"; - private static string GetOccurrenceKey(IDateTime dateTime) + private static CalDateTime GetRecurrenceId(CalendarEvent calendarEvent) + => calendarEvent?.RecurrenceIdentifier?.StartTime; + + private static string GetOccurrenceKey(CalDateTime dateTime) => dateTime.AsUtc.ToString("yyyyMMdd'T'HHmmss'Z'"); - private static DateTimeOffset ToDateTimeOffset(IDateTime dateTime) - => dateTime?.AsDateTimeOffset ?? default; + private static DateTimeOffset ToDateTimeOffset(CalDateTime dateTime) + { + if (dateTime == null) + return default; + + if (dateTime.IsFloating) + { + var floatingValue = DateTime.SpecifyKind(dateTime.Value, DateTimeKind.Unspecified); + return new DateTimeOffset(floatingValue, TimeZoneInfo.Local.GetUtcOffset(floatingValue)); + } + + return new DateTimeOffset(DateTime.SpecifyKind(dateTime.AsUtc, DateTimeKind.Utc)); + } private static bool Overlaps(DateTimeOffset start, DateTimeOffset end, DateTimeOffset windowStart, DateTimeOffset windowEnd) { @@ -601,7 +624,7 @@ public sealed class CalDavClient : ICalDavClient .Where(a => a?.Trigger != null && a.Trigger.IsRelative && a.Trigger.Duration.HasValue) .Select(a => new CalDavEventReminder { - DurationInSeconds = (int)Math.Abs(a.Trigger.Duration.Value.TotalSeconds), + DurationInSeconds = (int)Math.Abs(a.Trigger.Duration.Value.ToTimeSpanUnspecified().TotalSeconds), ReminderType = string.Equals(a.Action, "EMAIL", StringComparison.OrdinalIgnoreCase) ? CalendarItemReminderType.Email : CalendarItemReminderType.Popup @@ -638,7 +661,7 @@ public sealed class CalDavClient : ICalDavClient }; } - private static string ResolveTimeZoneId(IDateTime sourceDateTime, DateTimeOffset parsedDateTime) + private static string ResolveTimeZoneId(CalDateTime sourceDateTime, DateTimeOffset parsedDateTime) { var explicitTimeZoneId = sourceDateTime?.TzId; if (!string.IsNullOrWhiteSpace(explicitTimeZoneId)) @@ -664,34 +687,26 @@ public sealed class CalDavClient : ICalDavClient if (sourceEvent.ExceptionDates != null) { - foreach (var periodList in sourceEvent.ExceptionDates) - { - var dates = periodList - .Where(p => p.StartTime != null) - .Select(p => p.StartTime.AsUtc.ToString("yyyyMMdd'T'HHmmss'Z'")) - .ToList(); + var dates = sourceEvent.ExceptionDates + .GetAllDates() + .Where(d => d != null) + .Select(d => d.AsUtc.ToString("yyyyMMdd'T'HHmmss'Z'")) + .ToList(); - if (dates.Count > 0) - { - recurrenceLines.Add($"EXDATE:{string.Join(",", dates)}"); - } - } + if (dates.Count > 0) + recurrenceLines.Add($"EXDATE:{string.Join(",", dates)}"); } if (sourceEvent.RecurrenceDates != null) { - foreach (var periodList in sourceEvent.RecurrenceDates) - { - var dates = periodList - .Where(p => p.StartTime != null) - .Select(p => p.StartTime.AsUtc.ToString("yyyyMMdd'T'HHmmss'Z'")) - .ToList(); + var dates = sourceEvent.RecurrenceDates + .GetAllPeriods() + .Where(p => p.StartTime != null) + .Select(p => p.StartTime.AsUtc.ToString("yyyyMMdd'T'HHmmss'Z'")) + .ToList(); - if (dates.Count > 0) - { - recurrenceLines.Add($"RDATE:{string.Join(",", dates)}"); - } - } + if (dates.Count > 0) + recurrenceLines.Add($"RDATE:{string.Join(",", dates)}"); } return recurrenceLines.Count == 0