Files
Wino-Mail/Wino.Core.ViewModels/PersonalizationPageViewModel.cs
T

400 lines
13 KiB
C#
Raw Normal View History

2024-04-18 01:44:37 +02:00
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System;
using System.ComponentModel;
2024-04-18 01:44:37 +02:00
using System.Linq;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Wino.Core.Domain;
2024-11-10 23:28:25 +01:00
using Wino.Core.Domain.Entities.Mail;
using Wino.Core.Domain.Entities.Shared;
2024-04-18 01:44:37 +02:00
using Wino.Core.Domain.Enums;
using Wino.Core.Domain.Interfaces;
2025-10-03 21:13:26 +02:00
using Wino.Core.Domain.Models.Navigation;
2024-04-18 01:44:37 +02:00
using Wino.Core.Domain.Models.Personalization;
2024-11-10 23:28:25 +01:00
using Wino.Core.ViewModels.Data;
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
namespace Wino.Core.ViewModels;
public partial class PersonalizationPageViewModel : CoreBaseViewModel
2024-04-18 01:44:37 +02:00
{
2025-02-16 11:54:23 +01:00
public IStatePersistanceService StatePersistenceService { get; }
public IPreferencesService PreferencesService { get; }
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
private readonly IDialogServiceBase _dialogService;
private readonly INewThemeService _newThemeService;
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
private bool isPropChangeDisabled = false;
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
// Sample mail copy to use in previewing mail display modes.
public MailCopy DemoPreviewMailCopy { get; } = new MailCopy()
{
FromName = "Sender Name",
FromAddress = "sender@wino.mail",
2025-02-16 11:54:23 +01:00
Subject = "Mail Subject",
PreviewText = "Thank you for using Wino Mail. We hope you enjoy the experience.",
};
public IMailItemDisplayInformation DemoPreviewMailItemInformation { get; }
2025-02-16 11:54:23 +01:00
#region Personalization
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
public bool IsSelectedWindowsAccentColor => SelectedAppColor == Colors.LastOrDefault();
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
public ObservableCollection<AppColorViewModel> Colors { get; set; } = [];
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
public List<ElementThemeContainer> ElementThemes { get; set; } =
[
2026-04-12 15:55:40 +02:00
new ElementThemeContainer(ApplicationElementTheme.Default, Translator.ElementTheme_Default),
2025-02-16 11:54:23 +01:00
new ElementThemeContainer(ApplicationElementTheme.Light, Translator.ElementTheme_Light),
new ElementThemeContainer(ApplicationElementTheme.Dark, Translator.ElementTheme_Dark),
];
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
public List<MailListDisplayMode> InformationDisplayModes { get; set; } =
[
MailListDisplayMode.Compact,
MailListDisplayMode.Medium,
MailListDisplayMode.Spacious
];
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
public List<AppThemeBase> AppThemes { get; set; }
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
[ObservableProperty]
private ElementThemeContainer selectedElementTheme;
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
[ObservableProperty]
private MailListDisplayMode selectedInfoDisplayMode;
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
private AppColorViewModel _selectedAppColor;
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
public AppColorViewModel SelectedAppColor
{
get => _selectedAppColor;
set
2024-04-18 01:44:37 +02:00
{
2025-02-16 11:54:23 +01:00
if (SetProperty(ref _selectedAppColor, value))
2024-04-18 01:44:37 +02:00
{
2025-02-16 11:54:23 +01:00
UseAccentColor = value == Colors?.LastOrDefault();
2024-04-18 01:44:37 +02:00
}
}
2025-02-16 11:54:23 +01:00
}
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
private bool _useAccentColor;
public bool UseAccentColor
{
get => _useAccentColor;
set
2024-04-18 01:44:37 +02:00
{
2025-02-16 11:54:23 +01:00
if (SetProperty(ref _useAccentColor, value))
2024-04-18 01:44:37 +02:00
{
2025-02-16 11:54:23 +01:00
if (value)
2024-04-18 01:44:37 +02:00
{
2025-02-16 11:54:23 +01:00
SelectedAppColor = Colors?.LastOrDefault();
}
else if (SelectedAppColor == Colors?.LastOrDefault())
{
// Unchecking from accent color.
SelectedAppColor = Colors?.FirstOrDefault();
2024-04-18 01:44:37 +02:00
}
}
}
2025-02-16 11:54:23 +01:00
}
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
// Allow app theme change for system themes.
public bool CanSelectElementTheme => SelectedAppTheme != null &&
(SelectedAppTheme.AppThemeType == AppThemeType.System || SelectedAppTheme.AppThemeType == AppThemeType.Custom);
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
private AppThemeBase _selectedAppTheme;
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
public AppThemeBase SelectedAppTheme
{
get => _selectedAppTheme;
set
2024-04-18 01:44:37 +02:00
{
2025-02-16 11:54:23 +01:00
if (SetProperty(ref _selectedAppTheme, value))
2024-04-18 01:44:37 +02:00
{
2025-02-16 11:54:23 +01:00
OnPropertyChanged(nameof(CanSelectElementTheme));
2025-02-16 11:43:30 +01:00
2025-02-16 11:54:23 +01:00
if (!CanSelectElementTheme)
{
SelectedElementTheme = null;
2024-04-18 01:44:37 +02:00
}
}
}
2025-02-16 11:54:23 +01:00
}
2024-04-18 01:44:37 +02:00
// Backdrop selection properties
[ObservableProperty]
public partial List<BackdropTypeWrapper> AvailableBackdropTypes { get; set; }
[ObservableProperty]
public partial BackdropTypeWrapper SelectedBackdropType { get; set; }
2025-02-16 11:54:23 +01:00
#endregion
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
[RelayCommand]
private void ResetMailListPaneLength()
{
StatePersistenceService.MailListPaneLength = 420;
_dialogService.InfoBarMessage(Translator.GeneralTitle_Info, Translator.Info_MailListSizeResetSuccessMessage, InfoBarMessageType.Success);
}
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
public AsyncRelayCommand CreateCustomThemeCommand { get; set; }
public PersonalizationPageViewModel(IDialogServiceBase dialogService,
IStatePersistanceService statePersistanceService,
INewThemeService newThemeService,
2025-02-16 11:54:23 +01:00
IPreferencesService preferencesService)
{
_dialogService = dialogService;
_newThemeService = newThemeService;
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
StatePersistenceService = statePersistanceService;
PreferencesService = preferencesService;
2025-02-16 11:35:43 +01:00
DemoPreviewMailItemInformation = new DemoMailItemDisplayInformation(
DemoPreviewMailCopy.FromName,
DemoPreviewMailCopy.FromAddress,
DemoPreviewMailCopy.Subject,
DemoPreviewMailCopy.PreviewText);
2025-02-16 11:54:23 +01:00
CreateCustomThemeCommand = new AsyncRelayCommand(CreateCustomThemeAsync);
}
2025-02-16 11:35:43 +01:00
2025-02-16 11:54:23 +01:00
private async Task CreateCustomThemeAsync()
{
bool isThemeCreated = await _dialogService.ShowCustomThemeBuilderDialogAsync();
2025-02-16 11:35:43 +01:00
2025-02-16 11:54:23 +01:00
if (isThemeCreated)
{
// Reload themes.
2025-02-16 11:35:43 +01:00
2025-02-16 11:54:23 +01:00
await InitializeSettingsAsync();
2025-02-16 11:43:30 +01:00
}
2025-02-16 11:54:23 +01:00
}
2026-04-14 00:59:30 +02:00
[RelayCommand]
private async Task DeleteCustomThemeAsync(AppThemeBase theme)
{
if (theme == null || theme.AppThemeType != AppThemeType.Custom)
{
return;
}
var shouldDelete = await _dialogService.ShowConfirmationDialogAsync(
string.Format(Translator.SettingsCustomTheme_DeleteConfirm_Message, theme.ThemeName),
Translator.SettingsCustomTheme_DeleteConfirm_Title,
Translator.Buttons_Delete);
if (!shouldDelete)
{
return;
}
var isDeleted = await _newThemeService.DeleteCustomThemeAsync(theme.Id);
if (!isDeleted)
{
_dialogService.InfoBarMessage(
Translator.GeneralTitle_Warning,
Translator.SettingsCustomTheme_DeleteMissing,
InfoBarMessageType.Warning);
return;
}
await InitializeSettingsAsync();
_dialogService.InfoBarMessage(
Translator.GeneralTitle_Info,
string.Format(Translator.SettingsCustomTheme_DeleteSuccess, theme.ThemeName),
InfoBarMessageType.Success);
}
2025-02-16 11:54:23 +01:00
private void InitializeColors()
{
2026-04-14 00:59:30 +02:00
Colors.Clear();
2025-02-16 11:54:23 +01:00
Colors.Add(new AppColorViewModel("#0078d7"));
Colors.Add(new AppColorViewModel("#00838c"));
Colors.Add(new AppColorViewModel("#e3008c"));
Colors.Add(new AppColorViewModel("#ca4f07"));
Colors.Add(new AppColorViewModel("#e81123"));
Colors.Add(new AppColorViewModel("#00819e"));
Colors.Add(new AppColorViewModel("#10893e"));
Colors.Add(new AppColorViewModel("#881798"));
Colors.Add(new AppColorViewModel("#c239b3"));
Colors.Add(new AppColorViewModel("#767676"));
Colors.Add(new AppColorViewModel("#e1b12c"));
Colors.Add(new AppColorViewModel("#16a085"));
Colors.Add(new AppColorViewModel("#0984e3"));
Colors.Add(new AppColorViewModel("#4a69bd"));
Colors.Add(new AppColorViewModel("#05c46b"));
// Add system accent color as last item.
2025-10-03 21:13:26 +02:00
Colors.Add(new AppColorViewModel(_newThemeService.GetSystemAccentColorHex(), true));
2025-02-16 11:54:23 +01:00
}
/// <summary>
/// Set selections from settings service.
/// </summary>
private void SetInitialValues()
{
2026-04-12 15:55:40 +02:00
SelectedElementTheme = ElementThemes.Find(a => a.NativeTheme == _newThemeService.RootTheme)
?? ElementThemes.FirstOrDefault();
2025-02-16 11:54:23 +01:00
SelectedInfoDisplayMode = PreferencesService.MailItemDisplayMode;
2025-10-03 21:13:26 +02:00
var currentAccentColor = _newThemeService.AccentColor;
2025-02-16 11:54:23 +01:00
bool isWindowsColor = string.IsNullOrEmpty(currentAccentColor);
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
if (isWindowsColor)
2024-04-18 01:44:37 +02:00
{
2025-02-16 11:54:23 +01:00
SelectedAppColor = Colors.LastOrDefault();
UseAccentColor = true;
2024-04-18 01:44:37 +02:00
}
2025-02-16 11:54:23 +01:00
else
SelectedAppColor = Colors.FirstOrDefault(a => a.Hex == currentAccentColor);
2024-04-18 01:44:37 +02:00
// Find selected theme, handling backward compatibility where theme ID might not exist
var currentThemeId = _newThemeService.CurrentApplicationThemeId;
2026-04-12 15:55:40 +02:00
SelectedAppTheme = currentThemeId.HasValue
? AppThemes.Find(a => a.Id == currentThemeId.Value) ?? AppThemes.FirstOrDefault()
: AppThemes.FirstOrDefault();
// Set the current backdrop from service - backdrop should be independent of theme selection
var currentBackdropType = _newThemeService.CurrentBackdropType;
SelectedBackdropType = AvailableBackdropTypes?.FirstOrDefault(x => x.BackdropType == currentBackdropType);
2025-02-16 11:54:23 +01:00
}
2024-04-18 01:44:37 +02:00
2025-10-03 21:13:26 +02:00
public override async void OnNavigatedTo(NavigationMode mode, object parameters)
2025-02-16 11:54:23 +01:00
{
2025-10-03 21:13:26 +02:00
base.OnNavigatedTo(mode, parameters);
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
await InitializeSettingsAsync();
}
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
private async Task InitializeSettingsAsync()
{
Deactivate();
2024-04-18 01:44:37 +02:00
2025-10-03 21:13:26 +02:00
AppThemes = await _newThemeService.GetAvailableThemesAsync();
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
OnPropertyChanged(nameof(AppThemes));
2024-04-18 01:44:37 +02:00
// Initialize backdrop types
AvailableBackdropTypes = _newThemeService.GetAvailableBackdropTypes();
2025-02-16 11:54:23 +01:00
InitializeColors();
SetInitialValues();
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
PropertyChanged -= PersonalizationSettingsUpdated;
PropertyChanged += PersonalizationSettingsUpdated;
2024-04-18 01:44:37 +02:00
2025-10-03 21:13:26 +02:00
_newThemeService.AccentColorChanged -= AccentColorChanged;
_newThemeService.ElementThemeChanged -= ElementThemeChanged;
2024-04-18 01:44:37 +02:00
2025-10-03 21:13:26 +02:00
_newThemeService.AccentColorChanged += AccentColorChanged;
_newThemeService.ElementThemeChanged += ElementThemeChanged;
2025-02-16 11:54:23 +01:00
}
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
private void AccentColorChanged(object sender, string e)
{
isPropChangeDisabled = true;
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
SelectedAppColor = Colors.FirstOrDefault(a => a.Hex == e);
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
isPropChangeDisabled = false;
}
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
private void ElementThemeChanged(object sender, ApplicationElementTheme e)
{
isPropChangeDisabled = true;
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
SelectedElementTheme = ElementThemes.Find(a => a.NativeTheme == e);
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
isPropChangeDisabled = false;
}
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
protected override void OnDeactivated()
{
base.OnDeactivated();
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
Deactivate();
}
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
private void Deactivate()
{
PropertyChanged -= PersonalizationSettingsUpdated;
2024-04-18 01:44:37 +02:00
2025-10-03 21:13:26 +02:00
_newThemeService.AccentColorChanged -= AccentColorChanged;
_newThemeService.ElementThemeChanged -= ElementThemeChanged;
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
if (AppThemes != null)
2025-02-16 11:35:43 +01:00
{
2025-02-16 11:54:23 +01:00
AppThemes.Clear();
AppThemes = null;
2024-04-18 01:44:37 +02:00
}
2025-02-16 11:54:23 +01:00
}
2025-02-16 11:43:30 +01:00
2025-02-16 11:54:23 +01:00
private void PersonalizationSettingsUpdated(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (isPropChangeDisabled)
return;
2025-02-16 11:43:30 +01:00
2025-02-16 11:54:23 +01:00
if (e.PropertyName == nameof(SelectedElementTheme) && SelectedElementTheme != null)
{
2025-10-03 21:13:26 +02:00
_newThemeService.RootTheme = SelectedElementTheme.NativeTheme;
2025-02-16 11:35:43 +01:00
}
2025-02-16 11:54:23 +01:00
else if (e.PropertyName == nameof(SelectedAppTheme))
2025-02-16 11:35:43 +01:00
{
// Set the theme ID, can be null if no theme is selected
_newThemeService.CurrentApplicationThemeId = SelectedAppTheme?.Id;
// Theme selection should not affect backdrop - they are independent settings
}
else if (e.PropertyName == nameof(SelectedBackdropType) && SelectedBackdropType != null)
{
_newThemeService.CurrentBackdropType = SelectedBackdropType.BackdropType;
2025-02-16 11:54:23 +01:00
}
else
{
if (e.PropertyName == nameof(SelectedInfoDisplayMode))
PreferencesService.MailItemDisplayMode = SelectedInfoDisplayMode;
else if (e.PropertyName == nameof(SelectedAppColor))
2025-10-03 21:13:26 +02:00
_newThemeService.AccentColor = SelectedAppColor.Hex;
2024-04-18 01:44:37 +02:00
}
}
private sealed class DemoMailItemDisplayInformation(
string fromName,
string fromAddress,
string subject,
string previewText) : IMailItemDisplayInformation
{
public string Subject { get; } = subject;
public string FromName { get; } = fromName;
public string FromAddress { get; } = fromAddress;
public string PreviewText { get; } = previewText;
public bool IsRead { get; } = false;
public bool IsDraft { get; } = false;
public bool HasAttachments { get; } = false;
public bool IsCalendarEvent { get; } = false;
public bool IsFlagged { get; } = false;
public DateTime CreationDate { get; } = DateTime.Now;
public Guid? ContactPictureFileId { get; } = null;
public bool ThumbnailUpdatedEvent { get; } = false;
public bool IsBusy { get; } = false;
public bool IsThreadExpanded { get; } = false;
2026-04-11 21:02:51 +02:00
public bool HasReadReceiptTracking { get; } = false;
public bool IsReadReceiptAcknowledged { get; } = false;
public string ReadReceiptDisplayText { get; } = string.Empty;
public AccountContact SenderContact { get; } = null;
event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged
{
add { }
remove { }
}
}
2024-04-18 01:44:37 +02:00
}