Some UI changes on settings.
This commit is contained in:
@@ -77,7 +77,7 @@ public static class CalendarRecurrenceSummaryFormatter
|
||||
|
||||
return string.Format(
|
||||
culture,
|
||||
Translator.GetTranslatedString("CalendarEventCompose_RecurringSummarySmart"),
|
||||
Translator.CalendarEventCompose_RecurringSummarySmart,
|
||||
cadenceSummary,
|
||||
weekdaySummary,
|
||||
timeSummary,
|
||||
|
||||
@@ -18,6 +18,11 @@ public interface IStatePersistanceService : INotifyPropertyChanged
|
||||
/// </summary>
|
||||
string CoreWindowTitle { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// App mode title shown in the title bar.
|
||||
/// </summary>
|
||||
string AppModeTitle { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// When only reader page is visible in small sized window.
|
||||
/// </summary>
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Wino.Core.Domain.Misc;
|
||||
|
||||
public static class CalendarColorPalette
|
||||
{
|
||||
private static readonly string[] FlatUiColorPalette =
|
||||
[
|
||||
"#E53935", "#D81B60", "#8E24AA", "#5E35B1", "#3949AB", "#1E88E5", "#039BE5", "#00ACC1", "#00897B", "#43A047",
|
||||
"#7CB342", "#C0CA33", "#FDD835", "#FFB300", "#FB8C00", "#F4511E", "#6D4C41", "#757575", "#546E7A", "#C62828",
|
||||
"#AD1457", "#6A1B9A", "#4527A0", "#283593", "#1565C0", "#0277BD", "#00838F", "#00695C", "#2E7D32", "#558B2F",
|
||||
"#9E9D24", "#F9A825", "#FF8F00", "#EF6C00", "#D84315", "#4E342E", "#616161", "#455A64", "#EF5350", "#EC407A",
|
||||
"#AB47BC", "#7E57C2", "#5C6BC0", "#42A5F5", "#29B6F6", "#26C6DA", "#26A69A", "#66BB6A", "#9CCC65", "#D4E157",
|
||||
"#FFEE58", "#FFCA28", "#FFA726", "#FF7043", "#8D6E63", "#BDBDBD", "#78909C", "#F06292", "#BA68C8", "#9575CD"
|
||||
];
|
||||
|
||||
public static IReadOnlyList<string> GetColors() => FlatUiColorPalette;
|
||||
|
||||
public static string GetDistinctColor(IEnumerable<string> usedColors)
|
||||
{
|
||||
var used = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
if (usedColors != null)
|
||||
{
|
||||
foreach (var color in usedColors)
|
||||
{
|
||||
if (TryNormalizeHexColor(color, out var normalized))
|
||||
{
|
||||
used.Add(normalized);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var color in FlatUiColorPalette)
|
||||
{
|
||||
if (!used.Contains(color))
|
||||
{
|
||||
return color;
|
||||
}
|
||||
}
|
||||
|
||||
return FlatUiColorPalette[0];
|
||||
}
|
||||
|
||||
private static bool TryNormalizeHexColor(string value, out string normalized)
|
||||
{
|
||||
normalized = null;
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var color = value.Trim();
|
||||
if (color.StartsWith('#'))
|
||||
{
|
||||
color = color[1..];
|
||||
}
|
||||
|
||||
if (color.Length != 6)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!int.TryParse(color, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out _))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
normalized = $"#{color.ToUpperInvariant()}";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -150,6 +150,7 @@
|
||||
"CalendarEventCompose_PickCalendarTitle": "Pick a calendar",
|
||||
"CalendarEventCompose_Recurring": "Recurring",
|
||||
"CalendarEventCompose_RecurringSummary": "Occurs every {0} {1}{2} {3} effective {4}{5}",
|
||||
"CalendarEventCompose_RecurringSummarySmart": "Occurs {0}{1} {2} effective {3}{4}",
|
||||
"CalendarEventCompose_RepeatEvery": "Repeat every",
|
||||
"CalendarEventCompose_SelectCalendar": "Select calendar",
|
||||
"CalendarEventCompose_SingleOccurrenceSummary": "Occurs on {0} {1}",
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using FluentAssertions;
|
||||
using Moq;
|
||||
using Wino.Core.Domain;
|
||||
@@ -5,6 +7,7 @@ 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.Misc;
|
||||
using Wino.Core.Tests.Helpers;
|
||||
using Wino.Services;
|
||||
using Xunit;
|
||||
@@ -49,6 +52,7 @@ public class AccountServiceTests : IAsyncLifetime
|
||||
calendars.Should().HaveCount(1);
|
||||
calendars[0].IsPrimary.Should().BeTrue();
|
||||
calendars[0].Name.Should().Be(Translator.AccountDetailsPage_TabCalendar);
|
||||
ColorHelpers.GetFlatColorPalette().Should().Contain(calendars[0].BackgroundColorHex);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -72,6 +76,49 @@ public class AccountServiceTests : IAsyncLifetime
|
||||
calendars.Should().BeEmpty();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CreateAccountAsync_ImapLocalOnly_AssignsDistinctCalendarColorsAcrossAccounts()
|
||||
{
|
||||
var firstAccountId = Guid.NewGuid();
|
||||
var secondAccountId = Guid.NewGuid();
|
||||
|
||||
await _accountService.CreateAccountAsync(
|
||||
CreateImapAccount(firstAccountId),
|
||||
new CustomServerInformation
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
AccountId = firstAccountId,
|
||||
CalendarSupportMode = ImapCalendarSupportMode.LocalOnly
|
||||
});
|
||||
|
||||
await _accountService.CreateAccountAsync(
|
||||
CreateImapAccount(secondAccountId),
|
||||
new CustomServerInformation
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
AccountId = secondAccountId,
|
||||
CalendarSupportMode = ImapCalendarSupportMode.LocalOnly
|
||||
});
|
||||
|
||||
var calendars = await _databaseService.Connection.Table<Wino.Core.Domain.Entities.Calendar.AccountCalendar>()
|
||||
.OrderBy(a => a.AccountId)
|
||||
.ToListAsync();
|
||||
|
||||
calendars.Should().HaveCount(2);
|
||||
calendars.Select(a => a.BackgroundColorHex).Should().OnlyHaveUniqueItems();
|
||||
calendars.Should().OnlyContain(a => ColorHelpers.GetFlatColorPalette().Contains(a.BackgroundColorHex));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FlatCalendarPalette_ProvidesAtLeastFiftyDistinctColors()
|
||||
{
|
||||
ColorHelpers.GetFlatColorPalette()
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.Count()
|
||||
.Should()
|
||||
.BeGreaterThanOrEqualTo(50);
|
||||
}
|
||||
|
||||
private static MailAccount CreateImapAccount(Guid accountId)
|
||||
{
|
||||
return new MailAccount
|
||||
|
||||
@@ -15,8 +15,9 @@ public partial class SettingOptionsPageViewModel : CoreBaseViewModel
|
||||
{
|
||||
private readonly INativeAppService _nativeAppService;
|
||||
private readonly IAccountService _accountService;
|
||||
private readonly IStoreRatingService _storeRatingService;
|
||||
|
||||
public string WebsiteUrl => AppUrls.Website;
|
||||
public string GitHubUrl => AppUrls.GitHub;
|
||||
public string PaypalUrl => AppUrls.Paypal;
|
||||
|
||||
[ObservableProperty]
|
||||
@@ -28,10 +29,13 @@ public partial class SettingOptionsPageViewModel : CoreBaseViewModel
|
||||
[ObservableProperty]
|
||||
public partial int AccountCount { get; set; }
|
||||
|
||||
public SettingOptionsPageViewModel(INativeAppService nativeAppService, IAccountService accountService)
|
||||
public SettingOptionsPageViewModel(INativeAppService nativeAppService,
|
||||
IAccountService accountService,
|
||||
IStoreRatingService storeRatingService)
|
||||
{
|
||||
_nativeAppService = nativeAppService;
|
||||
_accountService = accountService;
|
||||
_storeRatingService = storeRatingService;
|
||||
}
|
||||
|
||||
public override void OnNavigatedTo(NavigationMode mode, object parameters)
|
||||
@@ -86,4 +90,19 @@ public partial class SettingOptionsPageViewModel : CoreBaseViewModel
|
||||
Messenger.Send(new BreadcrumbNavigationRequested(pageTitle, pageType));
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task NavigateExternalAsync(object target)
|
||||
{
|
||||
if (target is not string stringTarget || string.IsNullOrWhiteSpace(stringTarget))
|
||||
return;
|
||||
|
||||
if (stringTarget == "Store")
|
||||
{
|
||||
await _storeRatingService.LaunchStorePageForReviewAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
await _nativeAppService.LaunchUriAsync(new Uri(stringTarget));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,105 +1,34 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Wino.Core.Domain.Misc;
|
||||
|
||||
namespace Wino.Core.Misc;
|
||||
|
||||
public static class ColorHelpers
|
||||
{
|
||||
private static readonly string[] FlatUiColorPalette =
|
||||
[
|
||||
"#B91C1C", "#C2410C", "#B45309", "#A16207", "#4D7C0F", "#15803D", "#047857", "#0F766E", "#0E7490", "#0369A1",
|
||||
"#1D4ED8", "#4338CA", "#6D28D9", "#7E22CE", "#A21CAF", "#BE185D", "#E11D48", "#DC2626", "#EA580C", "#D97706",
|
||||
"#CA8A04", "#65A30D", "#16A34A", "#059669", "#0D9488", "#0891B2", "#0284C7", "#2563EB", "#4F46E5", "#7C3AED",
|
||||
"#9333EA", "#C026D3", "#DB2777", "#F43F5E", "#EF4444", "#F97316", "#F59E0B", "#EAB308", "#84CC16", "#22C55E",
|
||||
"#10B981", "#14B8A6", "#06B6D4", "#0EA5E9", "#3B82F6", "#6366F1", "#8B5CF6", "#A855F7", "#D946EF", "#EC4899",
|
||||
"#FB7185", "#F87171", "#FB923C", "#FBBF24", "#FACC15", "#A3E635", "#4ADE80", "#34D399", "#2DD4BF", "#22D3EE",
|
||||
"#38BDF8", "#60A5FA", "#818CF8", "#A78BFA", "#C084FC", "#E879F9", "#F472B6", "#FDA4AF", "#FCA5A5", "#FDBA74",
|
||||
"#FCD34D", "#FDE047", "#BEF264", "#86EFAC", "#6EE7B7", "#5EEAD4", "#67E8F9", "#7DD3FC", "#93C5FD", "#A5B4FC",
|
||||
"#C4B5FD", "#D8B4FE", "#F0ABFC", "#F9A8D4", "#A16207", "#9A3412", "#7C2D12", "#6F1D1B", "#7F1D1D", "#881337",
|
||||
"#831843", "#701A75", "#581C87", "#312E81", "#1E3A8A", "#1D4ED8", "#155E75", "#134E4A", "#14532D", "#3F6212",
|
||||
"#365314", "#3F3F46", "#52525B", "#57534E", "#44403C", "#78716C", "#6B7280", "#4B5563", "#374151", "#1F2937",
|
||||
"#A16207", "#B45309", "#C2410C", "#9F1239", "#BE123C", "#C026D3", "#7E22CE", "#6D28D9", "#4338CA", "#1D4ED8"
|
||||
];
|
||||
|
||||
public static IReadOnlyList<string> GetFlatColorPalette() => FlatUiColorPalette;
|
||||
public static IReadOnlyList<string> GetFlatColorPalette() => CalendarColorPalette.GetColors();
|
||||
|
||||
public static string GenerateFlatColorHex() => GetDistinctFlatColorHex(Array.Empty<string>());
|
||||
|
||||
public static string GetDistinctFlatColorHex(IEnumerable<string> usedColors)
|
||||
{
|
||||
var used = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
if (usedColors != null)
|
||||
var palette = CalendarColorPalette.GetColors();
|
||||
var distinctColor = CalendarColorPalette.GetDistinctColor(usedColors);
|
||||
if (palette.Contains(distinctColor))
|
||||
{
|
||||
foreach (var color in usedColors)
|
||||
{
|
||||
if (TryNormalizeHexColor(color, out var normalized))
|
||||
{
|
||||
used.Add(normalized);
|
||||
}
|
||||
}
|
||||
return distinctColor;
|
||||
}
|
||||
|
||||
foreach (var color in FlatUiColorPalette)
|
||||
{
|
||||
if (!used.Contains(color))
|
||||
{
|
||||
return color;
|
||||
}
|
||||
}
|
||||
var candidate = AdjustColor(palette[0], 1);
|
||||
|
||||
var attempt = 0;
|
||||
while (attempt < 500)
|
||||
{
|
||||
var baseColor = FlatUiColorPalette[attempt % FlatUiColorPalette.Length];
|
||||
var cycle = (attempt / FlatUiColorPalette.Length) + 1;
|
||||
var candidate = AdjustColor(baseColor, cycle);
|
||||
|
||||
if (!used.Contains(candidate))
|
||||
{
|
||||
return candidate;
|
||||
}
|
||||
|
||||
attempt++;
|
||||
}
|
||||
|
||||
return "#5C7A8A";
|
||||
}
|
||||
|
||||
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 bool TryNormalizeHexColor(string value, out string normalized)
|
||||
{
|
||||
normalized = null;
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var color = value.Trim();
|
||||
if (color.StartsWith('#'))
|
||||
{
|
||||
color = color[1..];
|
||||
}
|
||||
|
||||
if (color.Length != 6)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!int.TryParse(color, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out _))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
normalized = $"#{color.ToUpperInvariant()}";
|
||||
return true;
|
||||
}
|
||||
|
||||
private static string AdjustColor(string hexColor, int cycle)
|
||||
{
|
||||
var color = ColorTranslator.FromHtml(hexColor);
|
||||
|
||||
@@ -331,6 +331,7 @@ public sealed partial class ImagePreviewControl : PersonPicture
|
||||
if (!IsActiveRefresh(refreshVersion, cancellationToken))
|
||||
return;
|
||||
|
||||
DisplayName = string.Empty;
|
||||
Initials = string.Empty;
|
||||
ProfilePicture = bitmapImage;
|
||||
}).ConfigureAwait(false);
|
||||
|
||||
@@ -188,7 +188,7 @@ public class NavigationService : NavigationServiceBase, INavigationService
|
||||
|
||||
// Update the application mode in state persistence service
|
||||
_statePersistanceService.ApplicationMode = mode;
|
||||
_statePersistanceService.CoreWindowTitle = mode == WinoApplicationMode.Calendar
|
||||
_statePersistanceService.AppModeTitle = mode == WinoApplicationMode.Calendar
|
||||
? "Wino Calendar"
|
||||
: "Wino Mail";
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ public class StatePersistenceService : ObservableObject, IStatePersistanceServic
|
||||
|
||||
private const string OpenPaneLengthKey = nameof(OpenPaneLengthKey);
|
||||
private const string MailListPaneLengthKey = nameof(MailListPaneLengthKey);
|
||||
private const string AppModeTitleKey = nameof(AppModeTitle);
|
||||
|
||||
private readonly IConfigurationService _configurationService;
|
||||
|
||||
@@ -22,6 +23,7 @@ public class StatePersistenceService : ObservableObject, IStatePersistanceServic
|
||||
|
||||
_openPaneLength = _configurationService.Get(OpenPaneLengthKey, 320d);
|
||||
_mailListPaneLength = _configurationService.Get(MailListPaneLengthKey, 420d);
|
||||
_appModeTitle = _configurationService.Get(AppModeTitleKey, "Wino Mail");
|
||||
_calendarDisplayType = EnsureValidCalendarDisplayType(_configurationService.Get(nameof(CalendarDisplayType), CalendarDisplayType.Week));
|
||||
_dayDisplayCount = _configurationService.Get(nameof(DayDisplayCount), 1);
|
||||
|
||||
@@ -144,6 +146,21 @@ public class StatePersistenceService : ObservableObject, IStatePersistanceServic
|
||||
}
|
||||
}
|
||||
|
||||
private string _appModeTitle;
|
||||
|
||||
public string AppModeTitle
|
||||
{
|
||||
get => _appModeTitle;
|
||||
set
|
||||
{
|
||||
if (SetProperty(ref _appModeTitle, value))
|
||||
{
|
||||
_configurationService.Set(AppModeTitleKey, value);
|
||||
UpdateAppWindowTitle();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private double _openPaneLength;
|
||||
public double OpenPaneLength
|
||||
{
|
||||
@@ -199,10 +216,15 @@ public class StatePersistenceService : ObservableObject, IStatePersistanceServic
|
||||
}
|
||||
|
||||
private void UpdateAppCoreWindowTitle()
|
||||
{
|
||||
OnPropertyChanged(nameof(CoreWindowTitle));
|
||||
}
|
||||
|
||||
private void UpdateAppWindowTitle()
|
||||
{
|
||||
if (WinoApplication.MainWindow != null)
|
||||
{
|
||||
WinoApplication.MainWindow.Title = CoreWindowTitle;
|
||||
WinoApplication.MainWindow.Title = AppModeTitle;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
<Grid Grid.RowSpan="2" Background="{ThemeResource WinoApplicationBackgroundColor}" />
|
||||
<TitleBar
|
||||
x:Name="ShellTitleBar"
|
||||
Title="{x:Bind StatePersistanceService.CoreWindowTitle, Mode=OneWay}"
|
||||
Title="{x:Bind StatePersistanceService.AppModeTitle, Mode=OneWay}"
|
||||
Margin="-2"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
VerticalContentAlignment="Stretch"
|
||||
@@ -34,7 +34,8 @@
|
||||
Background="Transparent"
|
||||
IsBackButtonVisible="{x:Bind StatePersistanceService.IsBackButtonVisible, Mode=OneWay}"
|
||||
IsPaneToggleButtonVisible="True"
|
||||
PaneToggleRequested="PaneButtonClicked">
|
||||
PaneToggleRequested="PaneButtonClicked"
|
||||
Subtitle="{x:Bind StatePersistanceService.CoreWindowTitle, Mode=OneWay}">
|
||||
<TitleBar.RightHeader>
|
||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||
<!-- Sync Status Button -->
|
||||
|
||||
@@ -68,7 +68,7 @@ public sealed partial class ShellWindow : WindowEx, IWinoShellWindow,
|
||||
ExitWinoCommand = new RelayCommand(ForceClose);
|
||||
|
||||
this.SetIcon("Assets/Wino_Icon.ico");
|
||||
Title = "Wino Mail";
|
||||
Title = StatePersistanceService.AppModeTitle;
|
||||
|
||||
SystemTrayIcon.ForceCreate();
|
||||
}
|
||||
@@ -122,6 +122,7 @@ public sealed partial class ShellWindow : WindowEx, IWinoShellWindow,
|
||||
AppModeSegmentedControl.SelectedIndex = targetMode == WinoApplicationMode.Mail ? 0 : 1;
|
||||
_isApplyingActivationMode = false;
|
||||
|
||||
StatePersistanceService.AppModeTitle = GetAppModeTitle(targetMode);
|
||||
NavigationService.ChangeApplicationMode(targetMode);
|
||||
}
|
||||
|
||||
@@ -317,6 +318,7 @@ public sealed partial class ShellWindow : WindowEx, IWinoShellWindow,
|
||||
AppModeSegmentedControl.SelectedIndex = mode == WinoApplicationMode.Mail ? 0 : 1;
|
||||
_isApplyingActivationMode = false;
|
||||
|
||||
StatePersistanceService.AppModeTitle = GetAppModeTitle(mode);
|
||||
NavigationService.ChangeApplicationMode(mode);
|
||||
RestoreFromTray();
|
||||
}
|
||||
@@ -371,4 +373,9 @@ public sealed partial class ShellWindow : WindowEx, IWinoShellWindow,
|
||||
_currentMode = selectedMode;
|
||||
NavigationService.ChangeApplicationMode(selectedMode);
|
||||
}
|
||||
|
||||
private static string GetAppModeTitle(WinoApplicationMode mode)
|
||||
=> mode == WinoApplicationMode.Calendar
|
||||
? "Wino Calendar"
|
||||
: "Wino Mail";
|
||||
}
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
x:Class="Wino.Views.AccountDetailsPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:accounts="using:Wino.Core.Domain.Models.Accounts"
|
||||
xmlns:abstract="using:Wino.Views.Abstract"
|
||||
xmlns:accounts="using:Wino.Core.Domain.Models.Accounts"
|
||||
xmlns:calendar="using:Wino.Core.Domain.Entities.Calendar"
|
||||
xmlns:controls="using:CommunityToolkit.WinUI.Controls"
|
||||
xmlns:controls1="using:Wino.Controls"
|
||||
xmlns:coreControls="using:Wino.Mail.WinUI.Controls"
|
||||
xmlns:data="using:Wino.Core.ViewModels.Data"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:data="using:Wino.Core.ViewModels.Data"
|
||||
xmlns:domain="using:Wino.Core.Domain"
|
||||
xmlns:folders="using:Wino.Core.Domain.Models.Folders"
|
||||
xmlns:helpers="using:Wino.Helpers"
|
||||
@@ -81,13 +81,9 @@
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<controls:SettingsExpander
|
||||
Description="{x:Bind ViewModel.Address, Mode=OneWay}"
|
||||
Header="{x:Bind ViewModel.AccountName, Mode=OneWay}">
|
||||
<controls:SettingsExpander Description="{x:Bind ViewModel.Address, Mode=OneWay}" Header="{x:Bind ViewModel.AccountName, Mode=OneWay}">
|
||||
<controls:SettingsExpander.HeaderIcon>
|
||||
<BitmapIcon
|
||||
ShowAsMonochrome="False"
|
||||
UriSource="{x:Bind ViewModel.ProviderIconPath, Mode=OneWay}" />
|
||||
<BitmapIcon ShowAsMonochrome="False" UriSource="{x:Bind ViewModel.ProviderIconPath, Mode=OneWay}" />
|
||||
</controls:SettingsExpander.HeaderIcon>
|
||||
<controls:SettingsExpander.Items>
|
||||
<controls:SettingsCard Description="{x:Bind domain:Translator.AccountEditDialog_Message}" Header="{x:Bind domain:Translator.AccountDetailsPage_Title}">
|
||||
@@ -132,6 +128,7 @@
|
||||
|
||||
<Button
|
||||
Grid.Row="1"
|
||||
Width="100"
|
||||
HorizontalAlignment="Right"
|
||||
Command="{x:Bind ViewModel.ResetColorCommand}"
|
||||
Content="{x:Bind domain:Translator.Buttons_Reset}" />
|
||||
@@ -310,6 +307,7 @@
|
||||
<SymbolIcon Symbol="Save" />
|
||||
</controls:SettingsCard.HeaderIcon>
|
||||
<Button
|
||||
Width="100"
|
||||
HorizontalAlignment="Right"
|
||||
Command="{x:Bind ViewModel.SaveChangesCommand}"
|
||||
Content="{x:Bind domain:Translator.Buttons_Save}"
|
||||
@@ -321,6 +319,7 @@
|
||||
<SymbolIcon Symbol="Delete" />
|
||||
</controls:SettingsCard.HeaderIcon>
|
||||
<Button
|
||||
Width="100"
|
||||
Background="Red"
|
||||
Command="{x:Bind ViewModel.DeleteAccountCommand}"
|
||||
Content="{x:Bind domain:Translator.Buttons_Delete}" />
|
||||
|
||||
@@ -63,7 +63,9 @@
|
||||
HorizontalContentAlignment="Left"
|
||||
Style="{StaticResource DefaultButtonStyle}">
|
||||
<Button.Flyout>
|
||||
<Flyout Placement="BottomEdgeAlignedLeft">
|
||||
<Flyout
|
||||
x:Name="CalendarSelectionFlyout"
|
||||
Placement="BottomEdgeAlignedLeft">
|
||||
<ScrollViewer MaxHeight="360">
|
||||
<ItemsControl ItemsSource="{x:Bind ViewModel.AvailableCalendarGroups, Mode=OneWay}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
|
||||
@@ -155,6 +155,7 @@ public sealed partial class CalendarEventComposePage : CalendarEventComposePageA
|
||||
if (e.ClickedItem is AccountCalendarViewModel calendar)
|
||||
{
|
||||
ViewModel.SelectedCalendar = calendar;
|
||||
CalendarSelectionFlyout.Hide();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -33,44 +33,93 @@
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Image
|
||||
Width="96"
|
||||
Height="96"
|
||||
VerticalAlignment="Center"
|
||||
Source="ms-appx:///Assets/AppEntries/MailAssets/Square150x150Logo.scale-100.png"
|
||||
Stretch="Uniform" />
|
||||
|
||||
<!-- App Info -->
|
||||
<StackPanel
|
||||
<Grid
|
||||
Grid.Column="1"
|
||||
Margin="20,0,0,0"
|
||||
Margin="8,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
Spacing="4">
|
||||
ColumnSpacing="12">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<StackPanel
|
||||
VerticalAlignment="Center"
|
||||
Orientation="Horizontal"
|
||||
Spacing="12">
|
||||
<Image
|
||||
Width="56"
|
||||
Height="56"
|
||||
VerticalAlignment="Top"
|
||||
Source="ms-appx:///Assets/AppEntries/MailAssets/Square150x150Logo.scale-100.png"
|
||||
Stretch="Uniform" />
|
||||
<StackPanel VerticalAlignment="Center">
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource TitleTextBlockStyle}"
|
||||
Text="Wino Mail" />
|
||||
<TextBlock
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||
Style="{StaticResource BodyTextBlockStyle}"
|
||||
Text="{x:Bind domain:Translator.SettingsOptions_HeroDescription}" />
|
||||
<TextBlock
|
||||
Margin="0,2,0,0"
|
||||
VerticalAlignment="Top"
|
||||
Foreground="{ThemeResource TextFillColorTertiaryBrush}"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{x:Bind ViewModel.VersionText, Mode=OneWay}" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel
|
||||
Margin="0,8,0,0"
|
||||
Grid.RowSpan="2"
|
||||
Grid.Column="2"
|
||||
Margin="0,12,0,0"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
Orientation="Horizontal"
|
||||
Spacing="8">
|
||||
<HyperlinkButton
|
||||
Content="{x:Bind ViewModel.WebsiteUrl, Mode=OneWay}"
|
||||
NavigateUri="{x:Bind ViewModel.WebsiteUrl, Mode=OneWay}" />
|
||||
<HyperlinkButton
|
||||
Content="{x:Bind domain:Translator.SettingsPaypal_Title}"
|
||||
NavigateUri="{x:Bind ViewModel.PaypalUrl, Mode=OneWay}" />
|
||||
Spacing="12">
|
||||
|
||||
<Button
|
||||
Command="{x:Bind ViewModel.NavigateExternalCommand}"
|
||||
CommandParameter="{x:Bind ViewModel.PaypalUrl, Mode=OneWay}"
|
||||
Style="{StaticResource DefaultButtonStyle}"
|
||||
ToolTipService.ToolTip="{x:Bind domain:Translator.SettingsPaypal_Title}">
|
||||
<Viewbox Width="18" Height="18">
|
||||
<Path
|
||||
Data="M385.52,51.09C363.84,26.52,324.71,16,274.63,16H129.25a20.75,20.75,0,0,0-20.54,17.48l-60.55,382a12.43,12.43,0,0,0,10.39,14.22,12.58,12.58,0,0,0,1.94.15h89.76l22.54-142.29-.7,4.46a20.67,20.67,0,0,1,20.47-17.46h42.65c83.77,0,149.36-33.86,168.54-131.8.57-2.9,1.05-5.72,1.49-8.48h0C410.94,98.06,405.19,73.41,385.52,51.09Z"
|
||||
Fill="{ThemeResource TextFillColorPrimaryBrush}"
|
||||
Stretch="Uniform" />
|
||||
</Viewbox>
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
Grid.Column="1"
|
||||
Command="{x:Bind ViewModel.NavigateExternalCommand}"
|
||||
CommandParameter="{x:Bind ViewModel.GitHubUrl, Mode=OneWay}"
|
||||
Style="{StaticResource DefaultButtonStyle}"
|
||||
ToolTipService.ToolTip="{x:Bind domain:Translator.SettingsAboutGithub_Title}">
|
||||
<StackPanel HorizontalAlignment="Center" Spacing="6">
|
||||
<Viewbox Width="18" Height="18">
|
||||
<Path
|
||||
Data="m 12.2135 0 c -6.7538 0 -12.2135 5.5 -12.2135 12.3042 c 0 5.439 3.4983 10.043 8.3513 11.6725 c 0.6067 0.1225 0.829 -0.2647 0.829 -0.5905 c 0 -0.2853 -0.02 -1.263 -0.02 -2.2817 c -3.3975 0.7335 -4.105 -1.4668 -4.105 -1.4668 c -0.546 -1.426 -1.355 -1.7925 -1.355 -1.7925 c -1.112 -0.7538 0.081 -0.7538 0.081 -0.7538 c 1.2335 0.0815 1.8807 1.263 1.8807 1.263 c 1.0918 1.874 2.851 1.3445 3.5587 1.0185 c 0.101 -0.7945 0.4247 -1.3445 0.7685 -1.65 c -2.7097 -0.2853 -5.5607 -1.3445 -5.5607 -6.0708 c 0 -1.3445 0.485 -2.4445 1.2535 -3.3 c -0.1212 -0.3055 -0.546 -1.5687 0.1215 -3.2595 c 0 0 1.0313 -0.326 3.3565 1.263 a 11.7425 11.7425 90 0 1 3.0535 -0.4075 c 1.0313 0 2.0825 0.1428 3.0533 0.4075 c 2.3255 -1.589 3.3567 -1.263 3.3567 -1.263 c 0.6675 1.6908 0.2425 2.954 0.1212 3.2595 c 0.7888 0.8555 1.2538 1.9555 1.2538 3.3 c 0 4.7263 -2.851 5.765 -5.581 6.0708 c 0.445 0.387 0.829 1.1202 0.829 2.2815 c 0 1.65 -0.02 2.9743 -0.02 3.3815 c 0 0.326 0.2225 0.7132 0.829 0.591 c 4.853 -1.63 8.3513 -6.2338 8.3513 -11.6728 c 0.02 -6.8043 -5.4598 -12.3043 -12.1933 -12.3043 z"
|
||||
Fill="{ThemeResource TextFillColorPrimaryBrush}"
|
||||
Stretch="Uniform" />
|
||||
</Viewbox>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
Grid.Column="2"
|
||||
Command="{x:Bind ViewModel.NavigateExternalCommand}"
|
||||
CommandParameter="Store"
|
||||
Style="{StaticResource AccentButtonStyle}"
|
||||
ToolTipService.ToolTip="{x:Bind domain:Translator.SettingsStore_Title}">
|
||||
<Viewbox Width="18" Height="18">
|
||||
<Path
|
||||
Data="F1 M 19.003906 3.251953 L 19.003906 15.947266 C 19.003906 16.357422 18.920898 16.748047 18.754883 17.119141 C 18.588867 17.490234 18.367512 17.814127 18.09082 18.09082 C 17.814127 18.367514 17.490234 18.588867 17.119141 18.754883 C 16.748047 18.920898 16.357422 19.003906 15.947266 19.003906 L 3.056641 19.003906 C 2.646484 19.003906 2.255859 18.920898 1.884766 18.754883 C 1.513672 18.588867 1.189779 18.367514 0.913086 18.09082 C 0.636393 17.814127 0.415039 17.490234 0.249023 17.119141 C 0.083008 16.748047 0 16.357422 0 15.947266 L 0 3.251953 C 0 3.076172 0.032552 2.913412 0.097656 2.763672 C 0.16276 2.613934 0.252279 2.482098 0.366211 2.368164 C 0.480143 2.254232 0.611979 2.164715 0.761719 2.099609 C 0.911458 2.034506 1.074219 2.001953 1.25 2.001953 L 4.003906 2.001953 L 4.003906 0.996094 C 4.003906 0.859375 4.029948 0.730795 4.082031 0.610352 C 4.134114 0.48991 4.205729 0.384115 4.296875 0.292969 C 4.388021 0.201824 4.493815 0.130209 4.614258 0.078125 C 4.7347 0.026043 4.863281 0 5 0 L 14.003906 0 C 14.140624 0 14.269205 0.026043 14.389648 0.078125 C 14.510091 0.130209 14.615885 0.201824 14.707031 0.292969 C 14.798177 0.384115 14.869791 0.48991 14.921875 0.610352 C 14.973957 0.730795 14.999999 0.859375 15 0.996094 L 15 2.001953 L 17.753906 2.001953 C 17.923176 2.001953 18.084309 2.034506 18.237305 2.099609 C 18.390299 2.164715 18.523762 2.254232 18.637695 2.368164 C 18.751627 2.482098 18.841145 2.615561 18.90625 2.768555 C 18.971354 2.921551 19.003906 3.082684 19.003906 3.251953 Z M 14.003906 0.996094 L 5 0.996094 L 5 2.001953 L 14.003906 2.001953 Z M 5 10 L 9.003906 10 L 9.003906 5.996094 L 5 5.996094 Z M 10 10 L 14.003906 10 L 14.003906 5.996094 L 10 5.996094 Z M 5 15 L 9.003906 15 L 9.003906 10.996094 L 5 10.996094 Z M 10 15 L 14.003906 15 L 14.003906 10.996094 L 10 10.996094 Z "
|
||||
Fill="{ThemeResource AccentTextFillColorPrimaryBrush}"
|
||||
Stretch="Uniform" />
|
||||
</Viewbox>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<!-- Account Management Card -->
|
||||
<controls:SettingsCard
|
||||
|
||||
@@ -12,6 +12,7 @@ using Wino.Core.Domain.Entities.Shared;
|
||||
using Wino.Core.Domain.Enums;
|
||||
using Wino.Core.Domain.Interfaces;
|
||||
using Wino.Core.Domain.Models.Accounts;
|
||||
using Wino.Core.Domain.Misc;
|
||||
using Wino.Messaging.Client.Calendar;
|
||||
using Wino.Messaging.Client.Accounts;
|
||||
using Wino.Messaging.UI;
|
||||
@@ -20,22 +21,6 @@ namespace Wino.Services;
|
||||
|
||||
public class AccountService : BaseDatabaseService, IAccountService
|
||||
{
|
||||
private static readonly string[] DefaultCalendarFlatColors =
|
||||
[
|
||||
"#B91C1C",
|
||||
"#15803D",
|
||||
"#0E7490",
|
||||
"#1D4ED8",
|
||||
"#7C3AED",
|
||||
"#C026D3",
|
||||
"#EC4899",
|
||||
"#F97316",
|
||||
"#EAB308",
|
||||
"#22C55E",
|
||||
"#06B6D4",
|
||||
"#60A5FA"
|
||||
];
|
||||
|
||||
public IAuthenticator ExternalAuthenticationAuthenticator { get; set; }
|
||||
|
||||
private readonly ISignatureService _signatureService;
|
||||
@@ -657,20 +642,20 @@ public class AccountService : BaseDatabaseService, IAccountService
|
||||
IsExtended = true,
|
||||
RemoteCalendarId = string.Empty,
|
||||
TimeZone = string.Empty,
|
||||
BackgroundColorHex = GetDefaultCalendarFlatColor(accountId),
|
||||
BackgroundColorHex = await GetNextDistinctCalendarColorAsync().ConfigureAwait(false),
|
||||
TextColorHex = "#FFFFFF"
|
||||
};
|
||||
|
||||
await Connection.InsertAsync(localCalendar, typeof(AccountCalendar)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private static string GetDefaultCalendarFlatColor(Guid accountId)
|
||||
private async Task<string> GetNextDistinctCalendarColorAsync()
|
||||
{
|
||||
var bytes = accountId.ToByteArray();
|
||||
var hash = BitConverter.ToUInt32(bytes, 0);
|
||||
var index = (int)(hash % (uint)DefaultCalendarFlatColors.Length);
|
||||
var usedColors = await Connection.Table<AccountCalendar>()
|
||||
.ToListAsync()
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return DefaultCalendarFlatColors[index];
|
||||
return CalendarColorPalette.GetDistinctColor(usedColors.Select(a => a.BackgroundColorHex));
|
||||
}
|
||||
|
||||
public async Task UpdateAccountOrdersAsync(Dictionary<Guid, int> accountIdOrderPair)
|
||||
|
||||
Reference in New Issue
Block a user