Event compose implementation.
This commit is contained in:
@@ -35,9 +35,6 @@ public partial class CalendarAccountSettingsPageViewModel : CalendarBaseViewMode
|
||||
[ObservableProperty]
|
||||
public partial bool IsSyncEnabled { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial bool IsPrimaryCalendar { get; set; }
|
||||
|
||||
public ObservableCollection<ShowAsOption> ShowAsOptions { get; } = new ObservableCollection<ShowAsOption>();
|
||||
|
||||
[ObservableProperty]
|
||||
@@ -82,7 +79,6 @@ public partial class CalendarAccountSettingsPageViewModel : CalendarBaseViewMode
|
||||
// Initialize properties from AccountCalendar
|
||||
AccountColorHex = AccountCalendar.BackgroundColorHex ?? "#0078D4";
|
||||
IsSyncEnabled = AccountCalendar.IsSynchronizationEnabled;
|
||||
IsPrimaryCalendar = AccountCalendar.IsPrimary;
|
||||
SelectedDefaultShowAsOption = ShowAsOptions.FirstOrDefault(o => o.ShowAs == AccountCalendar.DefaultShowAs) ?? ShowAsOptions[2];
|
||||
}
|
||||
|
||||
@@ -104,15 +100,6 @@ public partial class CalendarAccountSettingsPageViewModel : CalendarBaseViewMode
|
||||
}
|
||||
}
|
||||
|
||||
partial void OnIsPrimaryCalendarChanged(bool value)
|
||||
{
|
||||
if (AccountCalendar != null)
|
||||
{
|
||||
AccountCalendar.IsPrimary = value;
|
||||
SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
|
||||
partial void OnSelectedDefaultShowAsOptionChanged(ShowAsOption value)
|
||||
{
|
||||
if (AccountCalendar != null && value != null)
|
||||
|
||||
@@ -9,6 +9,7 @@ using CommunityToolkit.Mvvm.Input;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using Serilog;
|
||||
using Wino.Calendar.ViewModels.Data;
|
||||
using Wino.Core.Domain.Entities.Calendar;
|
||||
using Wino.Calendar.ViewModels.Interfaces;
|
||||
using Wino.Core.Domain;
|
||||
using Wino.Core.Domain.Collections;
|
||||
@@ -122,12 +123,14 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel,
|
||||
if (mode == NavigationMode.Back)
|
||||
{
|
||||
await InitializeAccountCalendarsAsync();
|
||||
ValidateConfiguredNewEventCalendar();
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateDateNavigationHeaderItems();
|
||||
|
||||
await InitializeAccountCalendarsAsync();
|
||||
ValidateConfiguredNewEventCalendar();
|
||||
|
||||
await ShowWhatIsNewIfNeededAsync();
|
||||
|
||||
@@ -311,25 +314,31 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel,
|
||||
[RelayCommand]
|
||||
private async Task NewEventAsync()
|
||||
{
|
||||
var availableGroups = AccountCalendarStateService.GroupedAccountCalendars
|
||||
.Where(group => group.AccountCalendars.Count > 0)
|
||||
.Select(group => new CalendarPickerAccountGroup
|
||||
{
|
||||
Account = group.Account,
|
||||
Calendars = group.AccountCalendars.Select(calendar => calendar.AccountCalendar).ToList()
|
||||
})
|
||||
.ToList();
|
||||
var pickedCalendar = TryResolveConfiguredNewEventCalendar();
|
||||
|
||||
if (availableGroups.Count == 0)
|
||||
if (pickedCalendar == null)
|
||||
{
|
||||
_dialogService.InfoBarMessage(
|
||||
Translator.CalendarEventCompose_NoCalendarsTitle,
|
||||
Translator.CalendarEventCompose_NoCalendarsMessage,
|
||||
InfoBarMessageType.Warning);
|
||||
return;
|
||||
var availableGroups = AccountCalendarStateService.GroupedAccountCalendars
|
||||
.Where(group => group.AccountCalendars.Count > 0)
|
||||
.Select(group => new CalendarPickerAccountGroup
|
||||
{
|
||||
Account = group.Account,
|
||||
Calendars = group.AccountCalendars.Select(calendar => calendar.AccountCalendar).ToList()
|
||||
})
|
||||
.ToList();
|
||||
|
||||
if (availableGroups.Count == 0)
|
||||
{
|
||||
_dialogService.InfoBarMessage(
|
||||
Translator.CalendarEventCompose_NoCalendarsTitle,
|
||||
Translator.CalendarEventCompose_NoCalendarsMessage,
|
||||
InfoBarMessageType.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
pickedCalendar = await _dialogService.ShowSingleCalendarPickerDialogAsync(availableGroups);
|
||||
}
|
||||
|
||||
var pickedCalendar = await _dialogService.ShowSingleCalendarPickerDialogAsync(availableGroups);
|
||||
if (pickedCalendar == null)
|
||||
return;
|
||||
|
||||
@@ -472,7 +481,43 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel,
|
||||
}
|
||||
|
||||
public async void Receive(AccountRemovedMessage message)
|
||||
=> await InitializeAccountCalendarsAsync();
|
||||
{
|
||||
await InitializeAccountCalendarsAsync();
|
||||
ValidateConfiguredNewEventCalendar();
|
||||
}
|
||||
|
||||
private AccountCalendar TryResolveConfiguredNewEventCalendar()
|
||||
{
|
||||
ValidateConfiguredNewEventCalendar();
|
||||
|
||||
if (PreferencesService.NewEventButtonBehavior != NewEventButtonBehavior.AlwaysUseSpecificCalendar
|
||||
|| !PreferencesService.DefaultNewEventCalendarId.HasValue)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return AccountCalendarStateService.AllCalendars
|
||||
.FirstOrDefault(calendar => calendar.Id == PreferencesService.DefaultNewEventCalendarId.Value)?
|
||||
.AccountCalendar;
|
||||
}
|
||||
|
||||
private void ValidateConfiguredNewEventCalendar()
|
||||
{
|
||||
if (PreferencesService.NewEventButtonBehavior != NewEventButtonBehavior.AlwaysUseSpecificCalendar
|
||||
|| !PreferencesService.DefaultNewEventCalendarId.HasValue)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var exists = AccountCalendarStateService.AllCalendars
|
||||
.Any(calendar => calendar.Id == PreferencesService.DefaultNewEventCalendarId.Value);
|
||||
|
||||
if (exists)
|
||||
return;
|
||||
|
||||
PreferencesService.NewEventButtonBehavior = NewEventButtonBehavior.AskEachTime;
|
||||
PreferencesService.DefaultNewEventCalendarId = null;
|
||||
}
|
||||
|
||||
private static (DateTime StartDate, DateTime EndDate) GetDefaultComposeDateRange()
|
||||
{
|
||||
|
||||
@@ -6,18 +6,20 @@ using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Mail;
|
||||
using System.Threading.Tasks;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using EmailValidation;
|
||||
using Wino.Calendar.ViewModels.Data;
|
||||
using Wino.Core.Domain;
|
||||
using Wino.Core.Domain.Entities.Calendar;
|
||||
using Wino.Core.Domain.Entities.Shared;
|
||||
using Wino.Core.Domain.Enums;
|
||||
using Wino.Core.Domain.Exceptions;
|
||||
using Wino.Core.Domain.Interfaces;
|
||||
using Wino.Core.Domain.Models.Calendar;
|
||||
using Wino.Core.Domain.Models.Navigation;
|
||||
using Wino.Core.Domain.Validation;
|
||||
using Wino.Core.ViewModels;
|
||||
|
||||
namespace Wino.Calendar.ViewModels;
|
||||
@@ -31,10 +33,12 @@ public partial class CalendarEventComposePageViewModel : CalendarBaseViewModel
|
||||
private readonly IContactService _contactService;
|
||||
private readonly IPreferencesService _preferencesService;
|
||||
private readonly IUnderlyingThemeService _underlyingThemeService;
|
||||
private readonly CalendarEventComposeResultValidator _composeResultValidator = new();
|
||||
|
||||
public Func<Task<string>> GetHtmlNotesAsync { get; set; }
|
||||
|
||||
public ObservableCollection<AccountCalendarViewModel> AvailableCalendars { get; } = [];
|
||||
public ObservableCollection<GroupedAccountCalendarViewModel> AvailableCalendarGroups { get; } = [];
|
||||
public ObservableCollection<CalendarComposeAttendeeViewModel> Attendees { get; } = [];
|
||||
public ObservableCollection<CalendarComposeAttachmentViewModel> Attachments { get; } = [];
|
||||
public ObservableCollection<ShowAsOption> ShowAsOptions { get; } = [];
|
||||
@@ -97,6 +101,8 @@ public partial class CalendarEventComposePageViewModel : CalendarBaseViewModel
|
||||
public CalendarSettings CurrentSettings { get; }
|
||||
public string TimePickerClockIdentifier => CurrentSettings.DayHeaderDisplayType == DayHeaderDisplayType.TwentyFourHour ? "24HourClock" : "12HourClock";
|
||||
public bool HasAttachments => Attachments.Count > 0;
|
||||
public string SelectedCalendarDisplayText => SelectedCalendar?.Name ?? Translator.CalendarEventCompose_SelectCalendar;
|
||||
public string SelectedCalendarAccountText => SelectedCalendar?.Account?.Address ?? string.Empty;
|
||||
|
||||
public CalendarEventComposePageViewModel(IAccountService accountService,
|
||||
ICalendarService calendarService,
|
||||
@@ -169,11 +175,13 @@ public partial class CalendarEventComposePageViewModel : CalendarBaseViewModel
|
||||
|
||||
partial void OnSelectedCalendarChanged(AccountCalendarViewModel value)
|
||||
{
|
||||
if (value == null || SelectedShowAsOption != null)
|
||||
if (value == null)
|
||||
return;
|
||||
|
||||
SelectedShowAsOption = ShowAsOptions.FirstOrDefault(option => option.ShowAs == value.DefaultShowAs)
|
||||
?? ShowAsOptions.FirstOrDefault();
|
||||
OnPropertyChanged(nameof(SelectedCalendarDisplayText));
|
||||
OnPropertyChanged(nameof(SelectedCalendarAccountText));
|
||||
}
|
||||
|
||||
partial void OnIsAllDayChanged(bool value)
|
||||
@@ -263,36 +271,24 @@ public partial class CalendarEventComposePageViewModel : CalendarBaseViewModel
|
||||
[RelayCommand]
|
||||
private async Task CreateAsync()
|
||||
{
|
||||
if (!await ValidateAsync())
|
||||
return;
|
||||
|
||||
var uniqueAttendees = Attendees
|
||||
.GroupBy(attendee => attendee.Email, StringComparer.OrdinalIgnoreCase)
|
||||
.Select(group => group.First())
|
||||
.ToList();
|
||||
|
||||
var htmlNotes = GetHtmlNotesAsync == null ? string.Empty : await GetHtmlNotesAsync();
|
||||
var effectiveStart = GetEffectiveStartDateTime();
|
||||
var effectiveEnd = GetEffectiveEndDateTime();
|
||||
var createdResult = await BuildResultAsync(uniqueAttendees);
|
||||
|
||||
LastCreatedResult = new CalendarEventComposeResult
|
||||
try
|
||||
{
|
||||
CalendarId = SelectedCalendar!.Id,
|
||||
AccountId = SelectedCalendar.Account.Id,
|
||||
Title = Title.Trim(),
|
||||
Location = Location?.Trim() ?? string.Empty,
|
||||
HtmlNotes = htmlNotes,
|
||||
StartDate = effectiveStart,
|
||||
EndDate = effectiveEnd,
|
||||
IsAllDay = IsAllDay,
|
||||
TimeZoneId = TimeZoneInfo.Local.Id,
|
||||
ShowAs = SelectedShowAsOption?.ShowAs ?? SelectedCalendar.DefaultShowAs,
|
||||
SelectedReminders = BuildSelectedReminders(),
|
||||
Attendees = BuildAttendees(uniqueAttendees),
|
||||
Attachments = Attachments.Select(attachment => attachment.ToDraftModel()).ToList(),
|
||||
Recurrence = BuildRecurrenceRule(),
|
||||
RecurrenceSummary = RecurrenceSummary
|
||||
};
|
||||
_composeResultValidator.Validate(createdResult);
|
||||
}
|
||||
catch (CalendarEventComposeValidationException ex)
|
||||
{
|
||||
ShowValidationMessage(ex.Message);
|
||||
return;
|
||||
}
|
||||
|
||||
LastCreatedResult = createdResult;
|
||||
|
||||
_navigationService.GoBack();
|
||||
}
|
||||
@@ -307,7 +303,7 @@ public partial class CalendarEventComposePageViewModel : CalendarBaseViewModel
|
||||
|
||||
public async Task<CalendarComposeAttendeeViewModel> GetAttendeeAsync(string tokenText)
|
||||
{
|
||||
if (!IsValidEmailAddress(tokenText))
|
||||
if (!EmailValidator.Validate(tokenText))
|
||||
return null;
|
||||
|
||||
var existing = Attendees.Any(attendee => attendee.Email.Equals(tokenText, StringComparison.OrdinalIgnoreCase));
|
||||
@@ -359,26 +355,38 @@ public partial class CalendarEventComposePageViewModel : CalendarBaseViewModel
|
||||
private async Task LoadAvailableCalendarsAsync()
|
||||
{
|
||||
var accountCalendars = new List<AccountCalendarViewModel>();
|
||||
var groupedCalendars = new List<GroupedAccountCalendarViewModel>();
|
||||
var accounts = await _accountService.GetAccountsAsync().ConfigureAwait(false);
|
||||
|
||||
foreach (var account in accounts)
|
||||
{
|
||||
var calendars = await _calendarService.GetAccountCalendarsAsync(account.Id).ConfigureAwait(false);
|
||||
var viewModels = calendars
|
||||
.Select(calendar => new AccountCalendarViewModel(account, calendar))
|
||||
.ToList();
|
||||
|
||||
foreach (var calendar in calendars)
|
||||
accountCalendars.AddRange(viewModels);
|
||||
|
||||
if (viewModels.Count > 0)
|
||||
{
|
||||
accountCalendars.Add(new AccountCalendarViewModel(account, calendar));
|
||||
groupedCalendars.Add(new GroupedAccountCalendarViewModel(account, viewModels));
|
||||
}
|
||||
}
|
||||
|
||||
await ExecuteUIThread(() =>
|
||||
{
|
||||
AvailableCalendars.Clear();
|
||||
AvailableCalendarGroups.Clear();
|
||||
|
||||
foreach (var calendar in accountCalendars.OrderBy(calendar => calendar.Account.Name).ThenBy(calendar => calendar.Name))
|
||||
{
|
||||
AvailableCalendars.Add(calendar);
|
||||
}
|
||||
|
||||
foreach (var group in groupedCalendars.OrderBy(group => group.Account.Name))
|
||||
{
|
||||
AvailableCalendarGroups.Add(group);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -424,68 +432,35 @@ public partial class CalendarEventComposePageViewModel : CalendarBaseViewModel
|
||||
AllDayEndDate = new DateTimeOffset((isAllDay ? endDate.Date : startDate.Date.AddDays(1)));
|
||||
}
|
||||
|
||||
private async Task<bool> ValidateAsync()
|
||||
private async Task<CalendarEventComposeResult> BuildResultAsync(List<CalendarComposeAttendeeViewModel> uniqueAttendees)
|
||||
{
|
||||
if (SelectedCalendar == null)
|
||||
{
|
||||
ShowValidationMessage(Translator.CalendarEventCompose_ValidationMissingCalendar);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(Title))
|
||||
{
|
||||
ShowValidationMessage(Translator.CalendarEventCompose_ValidationMissingTitle);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsAllDay)
|
||||
{
|
||||
if (AllDayEndDate.Date <= StartDate.Date)
|
||||
{
|
||||
ShowValidationMessage(Translator.CalendarEventCompose_ValidationInvalidAllDayRange);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (GetEffectiveEndDateTime() <= GetEffectiveStartDateTime())
|
||||
{
|
||||
ShowValidationMessage(Translator.CalendarEventCompose_ValidationInvalidTimeRange);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (RecurrenceEndDate.HasValue && RecurrenceEndDate.Value.Date < StartDate.Date)
|
||||
{
|
||||
ShowValidationMessage(Translator.CalendarEventCompose_ValidationInvalidRecurrenceEnd);
|
||||
return false;
|
||||
throw new CalendarEventComposeValidationException(Translator.CalendarEventCompose_ValidationInvalidRecurrenceEnd);
|
||||
}
|
||||
|
||||
var missingAttachments = Attachments
|
||||
.Where(attachment => !File.Exists(attachment.FilePath))
|
||||
.Select(attachment => attachment.FileName)
|
||||
.ToList();
|
||||
var htmlNotes = GetHtmlNotesAsync == null ? string.Empty : await GetHtmlNotesAsync();
|
||||
var effectiveStart = GetEffectiveStartDateTime();
|
||||
var effectiveEnd = GetEffectiveEndDateTime();
|
||||
|
||||
if (missingAttachments.Count > 0)
|
||||
return new CalendarEventComposeResult
|
||||
{
|
||||
ShowValidationMessage(string.Format(Translator.CalendarEventCompose_ValidationMissingAttachment, string.Join(", ", missingAttachments)));
|
||||
return false;
|
||||
}
|
||||
|
||||
var normalizedAttendees = Attendees
|
||||
.Where(attendee => !string.IsNullOrWhiteSpace(attendee.Email))
|
||||
.Select(attendee => attendee.Email.Trim())
|
||||
.ToList();
|
||||
|
||||
if (normalizedAttendees.Any(address => !IsValidEmailAddress(address)))
|
||||
{
|
||||
ShowValidationMessage(Translator.CalendarEventCompose_ValidationInvalidAttendee);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (GetHtmlNotesAsync != null)
|
||||
{
|
||||
await GetHtmlNotesAsync();
|
||||
}
|
||||
|
||||
return true;
|
||||
CalendarId = SelectedCalendar?.Id ?? Guid.Empty,
|
||||
AccountId = SelectedCalendar?.Account.Id ?? Guid.Empty,
|
||||
Title = Title.Trim(),
|
||||
Location = Location?.Trim() ?? string.Empty,
|
||||
HtmlNotes = htmlNotes,
|
||||
StartDate = effectiveStart,
|
||||
EndDate = effectiveEnd,
|
||||
IsAllDay = IsAllDay,
|
||||
TimeZoneId = TimeZoneInfo.Local.Id,
|
||||
ShowAs = SelectedShowAsOption?.ShowAs ?? SelectedCalendar?.DefaultShowAs ?? CalendarItemShowAs.Busy,
|
||||
SelectedReminders = BuildSelectedReminders(),
|
||||
Attendees = BuildAttendees(uniqueAttendees),
|
||||
Attachments = Attachments.Select(attachment => attachment.ToDraftModel()).ToList(),
|
||||
Recurrence = BuildRecurrenceRule(),
|
||||
RecurrenceSummary = RecurrenceSummary
|
||||
};
|
||||
}
|
||||
|
||||
private List<Reminder> BuildSelectedReminders()
|
||||
@@ -676,18 +651,6 @@ public partial class CalendarEventComposePageViewModel : CalendarBaseViewModel
|
||||
OnPropertyChanged(nameof(HasAttachments));
|
||||
}
|
||||
|
||||
private static bool IsValidEmailAddress(string address)
|
||||
{
|
||||
try
|
||||
{
|
||||
var parsedAddress = new MailAddress(address);
|
||||
return parsedAddress.Address.Equals(address, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public partial class CalendarComposeFrequencyOption : ObservableObject
|
||||
|
||||
@@ -1,20 +1,17 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using Wino.Calendar.ViewModels.Data;
|
||||
using Wino.Core.Domain;
|
||||
using Wino.Core.Domain.Entities.Shared;
|
||||
using Wino.Core.Domain.Enums;
|
||||
using Wino.Core.Domain.Interfaces;
|
||||
using Wino.Core.Domain.Translations;
|
||||
using Wino.Core.ViewModels;
|
||||
using Wino.Messaging.Client.Calendar;
|
||||
using Wino.Messaging.Client.Navigation;
|
||||
|
||||
namespace Wino.Calendar.ViewModels;
|
||||
|
||||
@@ -56,12 +53,21 @@ public partial class CalendarSettingsPageViewModel : CalendarBaseViewModel
|
||||
[ObservableProperty]
|
||||
public partial int SelectedDefaultSnoozeIndex { get; set; }
|
||||
|
||||
public ObservableCollection<MailAccount> Accounts { get; } = [];
|
||||
public ObservableCollection<CalendarNewEventBehaviorOption> NewEventBehaviorOptions { get; } = [];
|
||||
public ObservableCollection<AccountCalendarViewModel> AvailableNewEventCalendars { get; } = [];
|
||||
|
||||
[ObservableProperty]
|
||||
public partial CalendarNewEventBehaviorOption SelectedNewEventBehaviorOption { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial AccountCalendarViewModel SelectedNewEventCalendar { get; set; }
|
||||
|
||||
public bool ShouldShowSpecificNewEventCalendar => SelectedNewEventBehaviorOption?.Behavior == NewEventButtonBehavior.AlwaysUseSpecificCalendar;
|
||||
|
||||
public IPreferencesService PreferencesService { get; }
|
||||
private readonly ICalendarService _calendarService;
|
||||
private readonly IAccountService _accountService;
|
||||
|
||||
public ObservableCollection<MailAccount> Accounts { get; } = new ObservableCollection<MailAccount>();
|
||||
|
||||
private readonly bool _isLoaded = false;
|
||||
|
||||
public CalendarSettingsPageViewModel(IPreferencesService preferencesService, ICalendarService calendarService, IAccountService accountService)
|
||||
@@ -71,10 +77,8 @@ public partial class CalendarSettingsPageViewModel : CalendarBaseViewModel
|
||||
_accountService = accountService;
|
||||
|
||||
var currentLanguageLanguageCode = WinoTranslationDictionary.GetLanguageFileNameRelativePath(preferencesService.CurrentLanguage);
|
||||
|
||||
var cultureInfo = new CultureInfo(currentLanguageLanguageCode);
|
||||
|
||||
// Populate the day names list
|
||||
for (var i = 0; i < 7; i++)
|
||||
{
|
||||
DayNames.Add(cultureInfo.DateTimeFormat.DayNames[i]);
|
||||
@@ -89,7 +93,6 @@ public partial class CalendarSettingsPageViewModel : CalendarBaseViewModel
|
||||
WorkingDayStartIndex = DayNames.IndexOf(cultureInfo.DateTimeFormat.GetDayName(preferencesService.WorkingDayStart));
|
||||
WorkingDayEndIndex = DayNames.IndexOf(cultureInfo.DateTimeFormat.GetDayName(preferencesService.WorkingDayEnd));
|
||||
|
||||
// Initialize reminder options
|
||||
var predefinedMinutes = _calendarService.GetPredefinedReminderMinutes();
|
||||
ReminderOptions.Add("None");
|
||||
foreach (var minutes in predefinedMinutes)
|
||||
@@ -102,10 +105,9 @@ public partial class CalendarSettingsPageViewModel : CalendarBaseViewModel
|
||||
ReminderOptions.Add(displayText);
|
||||
}
|
||||
|
||||
// Set selected index based on current default reminder setting
|
||||
if (preferencesService.DefaultReminderDurationInSeconds == 0)
|
||||
{
|
||||
SelectedDefaultReminderIndex = 0; // None
|
||||
SelectedDefaultReminderIndex = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -123,35 +125,47 @@ public partial class CalendarSettingsPageViewModel : CalendarBaseViewModel
|
||||
var selectedSnoozeIndex = Array.IndexOf(supportedSnoozeMinutes, preferencesService.DefaultSnoozeDurationInMinutes);
|
||||
SelectedDefaultSnoozeIndex = selectedSnoozeIndex >= 0 ? selectedSnoozeIndex : 0;
|
||||
|
||||
NewEventBehaviorOptions.Add(new CalendarNewEventBehaviorOption(NewEventButtonBehavior.AskEachTime, Translator.CalendarSettings_NewEventBehavior_AskEachTime));
|
||||
NewEventBehaviorOptions.Add(new CalendarNewEventBehaviorOption(NewEventButtonBehavior.AlwaysUseSpecificCalendar, Translator.CalendarSettings_NewEventBehavior_AlwaysUseSpecificCalendar));
|
||||
SelectedNewEventBehaviorOption = NewEventBehaviorOptions.FirstOrDefault(option => option.Behavior == preferencesService.NewEventButtonBehavior)
|
||||
?? NewEventBehaviorOptions.First();
|
||||
|
||||
_isLoaded = true;
|
||||
|
||||
// Load accounts with calendar support
|
||||
LoadAccountsAsync();
|
||||
}
|
||||
|
||||
private async void LoadAccountsAsync()
|
||||
{
|
||||
var accounts = await _accountService.GetAccountsAsync();
|
||||
|
||||
var accounts = await _accountService.GetAccountsAsync().ConfigureAwait(false);
|
||||
var calendarsByAccount = new List<(MailAccount Account, List<AccountCalendarViewModel> Calendars)>();
|
||||
|
||||
foreach (var account in accounts)
|
||||
{
|
||||
var calendars = await _calendarService.GetAccountCalendarsAsync(account.Id).ConfigureAwait(false);
|
||||
calendarsByAccount.Add((account, calendars.Select(calendar => new AccountCalendarViewModel(account, calendar)).ToList()));
|
||||
}
|
||||
|
||||
await Dispatcher.ExecuteOnUIThread(() =>
|
||||
{
|
||||
Accounts.Clear();
|
||||
AvailableNewEventCalendars.Clear();
|
||||
|
||||
foreach (var account in accounts)
|
||||
{
|
||||
Accounts.Add(account);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void NavigateToAccountSettings(MailAccount account)
|
||||
{
|
||||
if (account == null) return;
|
||||
|
||||
Messenger.Send(new BreadcrumbNavigationRequested(
|
||||
string.Format(Translator.CalendarAccountSettings_Description, account.Name),
|
||||
WinoPage.CalendarAccountSettingsPage,
|
||||
account.Id));
|
||||
foreach (var accountCalendars in calendarsByAccount)
|
||||
{
|
||||
foreach (var calendar in accountCalendars.Calendars)
|
||||
{
|
||||
AvailableNewEventCalendars.Add(calendar);
|
||||
}
|
||||
}
|
||||
|
||||
ApplyStoredNewEventCalendarPreference();
|
||||
});
|
||||
}
|
||||
|
||||
partial void OnCellHourHeightChanged(double oldValue, double newValue) => SaveSettings();
|
||||
@@ -163,10 +177,17 @@ public partial class CalendarSettingsPageViewModel : CalendarBaseViewModel
|
||||
partial void OnWorkingDayEndIndexChanged(int value) => SaveSettings();
|
||||
partial void OnSelectedDefaultReminderIndexChanged(int value) => SaveSettings();
|
||||
partial void OnSelectedDefaultSnoozeIndexChanged(int value) => SaveSettings();
|
||||
partial void OnSelectedNewEventBehaviorOptionChanged(CalendarNewEventBehaviorOption value)
|
||||
{
|
||||
OnPropertyChanged(nameof(ShouldShowSpecificNewEventCalendar));
|
||||
SaveSettings();
|
||||
}
|
||||
partial void OnSelectedNewEventCalendarChanged(AccountCalendarViewModel value) => SaveSettings();
|
||||
|
||||
public void SaveSettings()
|
||||
{
|
||||
if (!_isLoaded) return;
|
||||
if (!_isLoaded)
|
||||
return;
|
||||
|
||||
PreferencesService.FirstDayOfWeek = SelectedFirstDayOfWeekIndex switch
|
||||
{
|
||||
@@ -209,10 +230,9 @@ public partial class CalendarSettingsPageViewModel : CalendarBaseViewModel
|
||||
PreferencesService.WorkingHourEnd = WorkingHourEnd;
|
||||
PreferencesService.HourHeight = CellHourHeight;
|
||||
|
||||
// Save default reminder setting
|
||||
if (SelectedDefaultReminderIndex == 0)
|
||||
{
|
||||
PreferencesService.DefaultReminderDurationInSeconds = 0; // None
|
||||
PreferencesService.DefaultReminderDurationInSeconds = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -228,6 +248,47 @@ public partial class CalendarSettingsPageViewModel : CalendarBaseViewModel
|
||||
PreferencesService.DefaultSnoozeDurationInMinutes = supportedSnoozeMinutes[selectedIndex];
|
||||
}
|
||||
|
||||
Messenger.Send(new CalendarSettingsUpdatedMessage());
|
||||
var newEventBehavior = SelectedNewEventBehaviorOption?.Behavior ?? NewEventButtonBehavior.AskEachTime;
|
||||
if (newEventBehavior == NewEventButtonBehavior.AlwaysUseSpecificCalendar && SelectedNewEventCalendar != null)
|
||||
{
|
||||
PreferencesService.NewEventButtonBehavior = NewEventButtonBehavior.AlwaysUseSpecificCalendar;
|
||||
PreferencesService.DefaultNewEventCalendarId = SelectedNewEventCalendar.Id;
|
||||
}
|
||||
else
|
||||
{
|
||||
PreferencesService.NewEventButtonBehavior = NewEventButtonBehavior.AskEachTime;
|
||||
PreferencesService.DefaultNewEventCalendarId = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyStoredNewEventCalendarPreference()
|
||||
{
|
||||
var configuredCalendarId = PreferencesService.DefaultNewEventCalendarId;
|
||||
var configuredCalendar = configuredCalendarId.HasValue
|
||||
? AvailableNewEventCalendars.FirstOrDefault(calendar => calendar.Id == configuredCalendarId.Value)
|
||||
: null;
|
||||
|
||||
if (PreferencesService.NewEventButtonBehavior == NewEventButtonBehavior.AlwaysUseSpecificCalendar && configuredCalendar == null)
|
||||
{
|
||||
SelectedNewEventBehaviorOption = NewEventBehaviorOptions.First(option => option.Behavior == NewEventButtonBehavior.AskEachTime);
|
||||
SelectedNewEventCalendar = null;
|
||||
return;
|
||||
}
|
||||
|
||||
SelectedNewEventCalendar = configuredCalendar
|
||||
?? AvailableNewEventCalendars.FirstOrDefault(calendar => calendar.IsPrimary)
|
||||
?? AvailableNewEventCalendars.FirstOrDefault();
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class CalendarNewEventBehaviorOption
|
||||
{
|
||||
public NewEventButtonBehavior Behavior { get; }
|
||||
public string DisplayText { get; }
|
||||
|
||||
public CalendarNewEventBehaviorOption(NewEventButtonBehavior behavior, string displayText)
|
||||
{
|
||||
Behavior = behavior;
|
||||
DisplayText = displayText;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="TimePeriodLibrary.NET" />
|
||||
<PackageReference Include="TimePeriodLibrary.NET" />
|
||||
<PackageReference Include="EmailValidation" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
Reference in New Issue
Block a user