Files
Wino-Mail/Wino.Calendar.ViewModels/CalendarAppShellViewModel.cs
T

601 lines
20 KiB
C#
Raw Normal View History

2026-03-08 11:22:41 +01:00
using System;
using System.Collections.Generic;
2024-11-10 23:28:25 +01:00
using System.Globalization;
2026-03-06 17:46:38 +01:00
using System.Linq;
using System.Threading;
2024-11-10 23:28:25 +01:00
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Messaging;
using Serilog;
using Wino.Calendar.ViewModels.Data;
2026-03-07 01:46:07 +01:00
using Wino.Core.Domain.Entities.Calendar;
using Wino.Calendar.ViewModels.Interfaces;
2026-03-06 17:46:38 +01:00
using Wino.Core.Domain;
using Wino.Core.Domain.Collections;
2024-11-10 23:28:25 +01:00
using Wino.Core.Domain.Enums;
2025-01-06 21:56:33 +01:00
using Wino.Core.Domain.Extensions;
2024-11-10 23:28:25 +01:00
using Wino.Core.Domain.Interfaces;
using Wino.Core.Domain.Models.Calendar;
2026-03-08 13:21:42 +01:00
using Wino.Core.Domain.Models;
2024-11-10 23:28:25 +01:00
using Wino.Core.Domain.Models.Navigation;
using Wino.Core.Domain.Models.Synchronization;
2024-11-10 23:28:25 +01:00
using Wino.Core.ViewModels;
using Wino.Messaging.Client.Calendar;
using Wino.Messaging.Client.Navigation;
using Wino.Messaging.Server;
using Wino.Messaging.UI;
2024-11-10 23:28:25 +01:00
2025-05-18 14:06:25 +02:00
namespace Wino.Calendar.ViewModels;
2025-12-26 20:46:48 +01:00
public partial class CalendarAppShellViewModel : CalendarBaseViewModel,
2025-05-18 14:06:25 +02:00
IRecipient<VisibleDateRangeChangedMessage>,
IRecipient<CalendarEnableStatusChangedMessage>,
IRecipient<NavigateManageAccountsRequested>,
IRecipient<CalendarDisplayTypeChangedMessage>,
IRecipient<AccountRemovedMessage>
2024-11-10 23:28:25 +01:00
{
2025-05-18 14:06:25 +02:00
public IPreferencesService PreferencesService { get; }
public IStatePersistanceService StatePersistenceService { get; }
public IAccountCalendarStateService AccountCalendarStateService { get; }
public INavigationService NavigationService { get; }
[ObservableProperty]
private int _selectedMenuItemIndex = -1;
[ObservableProperty]
private bool isCalendarEnabled;
2025-10-03 21:55:23 +02:00
2025-05-18 14:06:25 +02:00
/// <summary>
/// Gets or sets the display date of the calendar.
/// </summary>
[ObservableProperty]
private DateTimeOffset _displayDate;
/// <summary>
/// Gets or sets the highlighted range in the CalendarView and displayed date range in FlipView.
/// </summary>
[ObservableProperty]
private DateRange highlightedDateRange;
[ObservableProperty]
private ObservableRangeCollection<string> dateNavigationHeaderItems = [];
[ObservableProperty]
private int _selectedDateNavigationHeaderIndex;
public bool IsVerticalCalendar => StatePersistenceService.CalendarDisplayType == CalendarDisplayType.Month;
2026-03-08 11:22:41 +01:00
[ObservableProperty]
private bool isStoreUpdateItemVisible;
2025-05-18 14:06:25 +02:00
// For updating account calendars asynchronously.
private SemaphoreSlim _accountCalendarUpdateSemaphoreSlim = new(1);
2025-12-26 20:46:48 +01:00
public CalendarAppShellViewModel(IPreferencesService preferencesService,
2025-05-18 14:06:25 +02:00
IStatePersistanceService statePersistanceService,
IAccountService accountService,
ICalendarService calendarService,
IAccountCalendarStateService accountCalendarStateService,
2026-03-02 00:44:29 +01:00
INavigationService navigationService,
2026-03-06 17:46:38 +01:00
IMailDialogService dialogService,
2026-03-08 11:22:41 +01:00
IUpdateManager updateManager,
IStoreUpdateService storeUpdateService)
2024-11-10 23:28:25 +01:00
{
2025-05-18 14:06:25 +02:00
_accountService = accountService;
_calendarService = calendarService;
2026-03-02 00:44:29 +01:00
_dialogService = dialogService;
_updateManager = updateManager;
2026-03-08 11:22:41 +01:00
_storeUpdateService = storeUpdateService;
2025-05-18 14:06:25 +02:00
AccountCalendarStateService = accountCalendarStateService;
AccountCalendarStateService.AccountCalendarSelectionStateChanged += UpdateAccountCalendarRequested;
AccountCalendarStateService.CollectiveAccountGroupSelectionStateChanged += AccountCalendarStateCollectivelyChanged;
2025-05-18 14:06:25 +02:00
NavigationService = navigationService;
PreferencesService = preferencesService;
2024-11-10 23:28:25 +01:00
2025-05-18 14:06:25 +02:00
StatePersistenceService = statePersistanceService;
StatePersistenceService.StatePropertyChanged += PrefefencesChanged;
}
2024-11-10 23:28:25 +01:00
2026-01-20 00:30:24 +01:00
protected override void OnDispatcherAssigned()
2025-05-18 14:06:25 +02:00
{
2026-01-20 00:30:24 +01:00
base.OnDispatcherAssigned();
AccountCalendarStateService.Dispatcher = Dispatcher;
2026-03-08 11:22:41 +01:00
_ = RefreshFooterItemsAsync(false);
2025-05-18 14:06:25 +02:00
}
2025-05-18 14:06:25 +02:00
private void PrefefencesChanged(object sender, string e)
{
if (e == nameof(StatePersistenceService.CalendarDisplayType))
2024-11-10 23:28:25 +01:00
{
2025-05-18 14:06:25 +02:00
Messenger.Send(new CalendarDisplayTypeChangedMessage(StatePersistenceService.CalendarDisplayType));
2025-01-01 17:28:29 +01:00
2026-02-13 03:09:13 +01:00
UpdateDateNavigationHeaderItems();
2024-11-10 23:28:25 +01:00
2025-05-18 14:06:25 +02:00
// Change the calendar.
DateClicked(new CalendarViewDayClickedEventArgs(GetDisplayTypeSwitchDate()));
2024-11-10 23:28:25 +01:00
}
2025-05-18 14:06:25 +02:00
}
2024-11-10 23:28:25 +01:00
2026-03-08 11:22:41 +01:00
private async void PreferencesServiceChanged(object sender, string e)
{
if (e == nameof(IPreferencesService.IsStoreUpdateNotificationsEnabled))
{
await RefreshFooterItemsAsync(false);
}
}
2025-05-18 14:06:25 +02:00
public override async void OnNavigatedTo(NavigationMode mode, object parameters)
{
base.OnNavigatedTo(mode, parameters);
2024-11-10 23:28:25 +01:00
2026-03-08 11:22:41 +01:00
PreferencesService.PreferenceChanged -= PreferencesServiceChanged;
PreferencesService.PreferenceChanged += PreferencesServiceChanged;
await RefreshFooterItemsAsync(mode == NavigationMode.New);
2026-03-08 01:33:47 +01:00
// Preserve the existing calendar shell frame state when the user switches
// between Mail and Calendar modes. Back/forward restoration should not
// force a new CalendarPage navigation, otherwise pages like
// CalendarEventComposePage get dropped from the inner frame stack.
if (mode != NavigationMode.New)
{
2026-03-08 01:33:47 +01:00
UpdateDateNavigationHeaderItems();
await InitializeAccountCalendarsAsync();
2026-03-07 01:46:07 +01:00
ValidateConfiguredNewEventCalendar();
return;
}
2025-12-27 19:16:24 +01:00
2025-05-18 14:06:25 +02:00
UpdateDateNavigationHeaderItems();
2025-05-18 14:06:25 +02:00
await InitializeAccountCalendarsAsync();
2026-03-07 01:46:07 +01:00
ValidateConfiguredNewEventCalendar();
2026-03-02 00:44:29 +01:00
await ShowWhatIsNewIfNeededAsync();
2025-05-18 14:06:25 +02:00
TodayClicked();
}
2026-03-08 11:22:41 +01:00
public override void OnNavigatedFrom(NavigationMode mode, object parameters)
{
base.OnNavigatedFrom(mode, parameters);
PreferencesService.PreferenceChanged -= PreferencesServiceChanged;
}
2026-03-02 00:44:29 +01:00
private async Task ShowWhatIsNewIfNeededAsync()
{
if (!_updateManager.ShouldShowUpdateNotes())
return;
var notes = await _updateManager.GetLatestUpdateNotesAsync();
if (notes.Sections.Count == 0)
return;
await _dialogService.ShowWhatIsNewDialogAsync(notes);
}
2026-03-08 11:22:41 +01:00
private async Task RefreshFooterItemsAsync(bool showNotification)
{
await _storeUpdateService.RefreshAvailabilityAsync(showNotification).ConfigureAwait(false);
await ExecuteUIThread(() =>
{
IsStoreUpdateItemVisible = _storeUpdateService.HasAvailableUpdate && PreferencesService.IsStoreUpdateNotificationsEnabled;
});
}
private async Task StartStoreUpdateAsync()
{
await _storeUpdateService.StartUpdateAsync().ConfigureAwait(false);
await RefreshFooterItemsAsync(false).ConfigureAwait(false);
}
2025-05-18 14:06:25 +02:00
private async void AccountCalendarStateCollectivelyChanged(object sender, GroupedAccountCalendarViewModel e)
{
// When using three-state checkbox, multiple accounts will be selected/unselected at the same time.
// Reporting all these changes one by one to the UI is not efficient and may cause problems in the future.
2025-05-18 14:06:25 +02:00
// Update all calendar states at once.
try
{
await _accountCalendarUpdateSemaphoreSlim.WaitAsync();
2025-05-18 14:06:25 +02:00
foreach (var calendar in e.AccountCalendars)
{
2025-05-18 14:06:25 +02:00
await _calendarService.UpdateAccountCalendarAsync(calendar.AccountCalendar).ConfigureAwait(false);
}
}
2025-05-18 14:06:25 +02:00
catch (Exception ex)
{
2025-05-18 14:06:25 +02:00
Log.Error(ex, "Error while waiting for account calendar update semaphore.");
}
finally
{
_accountCalendarUpdateSemaphoreSlim.Release();
}
}
2025-05-18 14:06:25 +02:00
private async void UpdateAccountCalendarRequested(object sender, AccountCalendarViewModel e)
=> await _calendarService.UpdateAccountCalendarAsync(e.AccountCalendar).ConfigureAwait(false);
2025-05-18 14:06:25 +02:00
private async Task InitializeAccountCalendarsAsync()
{
await Dispatcher.ExecuteOnUIThread(() => AccountCalendarStateService.ClearGroupedAccountCalendars());
2025-05-18 14:06:25 +02:00
var accounts = await _accountService.GetAccountsAsync().ConfigureAwait(false);
2025-05-18 14:06:25 +02:00
foreach (var account in accounts)
{
var accountCalendars = await _calendarService.GetAccountCalendarsAsync(account.Id).ConfigureAwait(false);
var calendarViewModels = new List<AccountCalendarViewModel>();
2025-05-18 14:06:25 +02:00
foreach (var calendar in accountCalendars)
{
var calendarViewModel = new AccountCalendarViewModel(account, calendar);
2025-05-18 14:06:25 +02:00
calendarViewModels.Add(calendarViewModel);
}
2025-05-18 14:06:25 +02:00
var groupedAccountCalendarViewModel = new GroupedAccountCalendarViewModel(account, calendarViewModels);
await Dispatcher.ExecuteOnUIThread(() =>
{
AccountCalendarStateService.AddGroupedAccountCalendar(groupedAccountCalendarViewModel);
});
2024-11-10 23:28:25 +01:00
}
2025-05-18 14:06:25 +02:00
}
2024-11-10 23:28:25 +01:00
2025-05-18 14:06:25 +02:00
private void ForceNavigateCalendarDate()
{
2026-03-08 11:22:41 +01:00
var args = new CalendarPageNavigationArgs()
{
2026-03-08 11:22:41 +01:00
NavigationDate = _navigationDate ?? DateTime.Now.Date
};
2026-03-08 11:22:41 +01:00
NavigationService.Navigate(WinoPage.CalendarPage, args);
_navigationDate = null;
2025-05-18 14:06:25 +02:00
}
2025-05-18 14:06:25 +02:00
partial void OnSelectedMenuItemIndexChanged(int oldValue, int newValue)
{
2026-03-08 11:22:41 +01:00
if (newValue < 0)
return;
if (newValue == 0)
{
2026-03-08 11:22:41 +01:00
NavigationService.Navigate(WinoPage.ManageAccountsPage);
}
else if (newValue == 1)
{
NavigationService.Navigate(WinoPage.SettingsPage);
2025-05-18 14:06:25 +02:00
}
2026-03-08 11:22:41 +01:00
else if (IsStoreUpdateItemVisible && newValue == 2)
{
_ = StartStoreUpdateAsync();
}
SelectedMenuItemIndex = -1;
2025-05-18 14:06:25 +02:00
}
[RelayCommand]
private async Task Sync()
{
// Sync all calendars.
var accounts = await _accountService.GetAccountsAsync().ConfigureAwait(false);
2025-05-18 14:06:25 +02:00
foreach (var account in accounts)
{
var t = new NewCalendarSynchronizationRequested(new CalendarSynchronizationOptions()
2024-11-10 23:28:25 +01:00
{
2025-05-18 14:06:25 +02:00
AccountId = account.Id,
2026-02-18 20:43:10 +01:00
Type = CalendarSynchronizationType.CalendarEvents
2025-12-26 20:46:48 +01:00
});
2025-05-18 14:06:25 +02:00
Messenger.Send(t);
2024-11-10 23:28:25 +01:00
}
2025-05-18 14:06:25 +02:00
}
2024-11-10 23:28:25 +01:00
2025-05-18 14:06:25 +02:00
/// <summary>
/// When calendar type switches, we need to navigate to the most ideal date.
/// This method returns that date.
/// </summary>
private DateTime GetDisplayTypeSwitchDate()
{
var settings = PreferencesService.GetCurrentCalendarSettings();
switch (StatePersistenceService.CalendarDisplayType)
2024-11-10 23:28:25 +01:00
{
2025-05-18 14:06:25 +02:00
case CalendarDisplayType.Day:
if (HighlightedDateRange.IsInRange(DateTime.Now)) return DateTime.Now.Date;
return HighlightedDateRange.StartDate;
case CalendarDisplayType.Week:
if (HighlightedDateRange == null || HighlightedDateRange.IsInRange(DateTime.Now))
{
return DateTime.Now.Date.GetWeekStartDateForDate(settings.FirstDayOfWeek);
}
2024-11-10 23:28:25 +01:00
2025-05-18 14:06:25 +02:00
return HighlightedDateRange.StartDate.GetWeekStartDateForDate(settings.FirstDayOfWeek);
case CalendarDisplayType.WorkWeek:
break;
case CalendarDisplayType.Month:
break;
default:
break;
2024-11-10 23:28:25 +01:00
}
2025-05-18 14:06:25 +02:00
return DateTime.Today.Date;
}
2025-05-18 14:06:25 +02:00
private DateTime? _navigationDate;
private readonly IAccountService _accountService;
private readonly ICalendarService _calendarService;
2026-03-06 17:46:38 +01:00
private readonly IMailDialogService _dialogService;
2026-03-02 00:44:29 +01:00
private readonly IUpdateManager _updateManager;
2026-03-08 11:22:41 +01:00
private readonly IStoreUpdateService _storeUpdateService;
2024-11-10 23:28:25 +01:00
2025-05-18 14:06:25 +02:00
#region Commands
2025-05-18 14:06:25 +02:00
[RelayCommand]
private void TodayClicked()
{
_navigationDate = DateTime.Now.Date;
2024-11-10 23:28:25 +01:00
2025-05-18 14:06:25 +02:00
ForceNavigateCalendarDate();
}
2024-11-10 23:28:25 +01:00
2025-05-18 14:06:25 +02:00
[RelayCommand]
public void ManageAccounts() => NavigationService.Navigate(WinoPage.AccountManagementPage);
2024-11-10 23:28:25 +01:00
2026-03-06 17:46:38 +01:00
[RelayCommand]
private async Task NewEventAsync()
{
2026-03-07 01:46:07 +01:00
var pickedCalendar = TryResolveConfiguredNewEventCalendar();
2026-03-06 17:46:38 +01:00
2026-03-07 01:46:07 +01:00
if (pickedCalendar == null)
2026-03-06 17:46:38 +01:00
{
2026-03-07 01:46:07 +01:00
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);
2026-03-06 17:46:38 +01:00
}
if (pickedCalendar == null)
return;
var (startDate, endDate) = GetDefaultComposeDateRange();
NavigationService.Navigate(WinoPage.CalendarEventComposePage, new CalendarEventComposeNavigationArgs
{
SelectedCalendarId = pickedCalendar.Id,
StartDate = startDate,
EndDate = endDate
});
}
2026-03-08 13:21:42 +01:00
public override async Task KeyboardShortcutHook(KeyboardShortcutTriggerDetails args)
{
if (args.Handled || args.Mode != WinoApplicationMode.Calendar)
return;
if (args.Action == KeyboardShortcutAction.NewEvent)
{
await NewEventAsync();
args.Handled = true;
}
}
2025-10-03 21:55:23 +02:00
2025-05-18 14:06:25 +02:00
[RelayCommand]
private void DateClicked(CalendarViewDayClickedEventArgs clickedDateArgs)
{
_navigationDate = clickedDateArgs.ClickedDate;
2024-11-10 23:28:25 +01:00
2025-05-18 14:06:25 +02:00
ForceNavigateCalendarDate();
}
2024-11-10 23:28:25 +01:00
2025-05-18 14:06:25 +02:00
#endregion
2024-11-10 23:28:25 +01:00
protected override void RegisterRecipients()
{
base.RegisterRecipients();
UnregisterRecipients();
Messenger.Register<VisibleDateRangeChangedMessage>(this);
Messenger.Register<CalendarEnableStatusChangedMessage>(this);
Messenger.Register<NavigateManageAccountsRequested>(this);
Messenger.Register<CalendarDisplayTypeChangedMessage>(this);
Messenger.Register<AccountRemovedMessage>(this);
}
protected override void UnregisterRecipients()
{
base.UnregisterRecipients();
Messenger.Unregister<VisibleDateRangeChangedMessage>(this);
Messenger.Unregister<CalendarEnableStatusChangedMessage>(this);
Messenger.Unregister<NavigateManageAccountsRequested>(this);
Messenger.Unregister<CalendarDisplayTypeChangedMessage>(this);
Messenger.Unregister<AccountRemovedMessage>(this);
}
2025-05-18 14:06:25 +02:00
public void Receive(VisibleDateRangeChangedMessage message) => HighlightedDateRange = message.DateRange;
2024-11-10 23:28:25 +01:00
2025-05-18 14:06:25 +02:00
/// <summary>
/// Sets the header navigation items based on visible date range and calendar type.
/// </summary>
private void UpdateDateNavigationHeaderItems()
{
2026-02-13 03:09:13 +01:00
var settings = PreferencesService.GetCurrentCalendarSettings();
var cultureInfo = settings.CultureInfo ?? CultureInfo.CurrentUICulture;
2024-11-10 23:28:25 +01:00
2026-02-13 03:09:13 +01:00
var visibleRange = HighlightedDateRange ?? new DateRange(DateTime.Today, DateTime.Today.AddDays(1));
var headerText = GetHeaderText(visibleRange, cultureInfo);
DateNavigationHeaderItems.ReplaceRange([headerText]);
SelectedDateNavigationHeaderIndex = DateNavigationHeaderItems.Count > 0 ? 0 : -1;
}
private string GetHeaderText(DateRange visibleRange, CultureInfo cultureInfo)
{
var startDate = visibleRange.StartDate.Date;
var endDate = visibleRange.EndDate.Date > startDate ? visibleRange.EndDate.Date.AddDays(-1) : startDate;
2024-11-10 23:28:25 +01:00
2025-05-18 14:06:25 +02:00
switch (StatePersistenceService.CalendarDisplayType)
{
case CalendarDisplayType.Day:
2026-02-13 03:09:13 +01:00
return startDate.ToString("MMMM d, dddd", cultureInfo);
2025-05-18 14:06:25 +02:00
case CalendarDisplayType.Week:
case CalendarDisplayType.WorkWeek:
2026-02-13 03:09:13 +01:00
if (startDate.Month == endDate.Month && startDate.Year == endDate.Year)
{
return $"{startDate.ToString("MMMM d", cultureInfo)} - {endDate.ToString("%d", cultureInfo)}";
}
return $"{startDate.ToString("MMMM d", cultureInfo)} - {endDate.ToString("MMMM d", cultureInfo)}";
2025-05-18 14:06:25 +02:00
case CalendarDisplayType.Month:
2026-02-13 03:09:13 +01:00
return GetDominantMonthHeaderText(startDate, endDate, cultureInfo);
2025-05-18 14:06:25 +02:00
default:
2026-02-13 03:09:13 +01:00
return startDate.ToString("d", cultureInfo);
2024-11-10 23:28:25 +01:00
}
2025-05-18 14:06:25 +02:00
}
2024-11-10 23:28:25 +01:00
2026-02-13 03:09:13 +01:00
private static string GetDominantMonthHeaderText(DateTime startDate, DateTime endDate, CultureInfo cultureInfo)
2025-05-18 14:06:25 +02:00
{
2026-02-13 03:09:13 +01:00
if (endDate < startDate)
{
endDate = startDate;
}
2024-11-10 23:28:25 +01:00
2026-02-13 03:09:13 +01:00
var monthDayCounts = new Dictionary<(int Year, int Month), int>();
for (var day = startDate; day <= endDate; day = day.AddDays(1))
2025-05-18 14:06:25 +02:00
{
2026-02-13 03:09:13 +01:00
var key = (day.Year, day.Month);
if (monthDayCounts.TryGetValue(key, out var count))
{
monthDayCounts[key] = count + 1;
}
else
{
monthDayCounts[key] = 1;
}
2024-11-10 23:28:25 +01:00
}
2026-02-13 03:09:13 +01:00
var dominantKey = (Year: startDate.Year, Month: startDate.Month);
var dominantCount = -1;
foreach (var pair in monthDayCounts)
{
if (pair.Value > dominantCount)
{
dominantCount = pair.Value;
dominantKey = pair.Key;
}
}
2025-05-18 14:06:25 +02:00
2026-02-13 03:09:13 +01:00
return new DateTime(dominantKey.Year, dominantKey.Month, 1).ToString("Y", cultureInfo);
2025-05-18 14:06:25 +02:00
}
2026-02-13 03:09:13 +01:00
partial void OnHighlightedDateRangeChanged(DateRange value) => UpdateDateNavigationHeaderItems();
2025-05-18 14:06:25 +02:00
public async void Receive(CalendarEnableStatusChangedMessage message)
=> await ExecuteUIThread(() => IsCalendarEnabled = message.IsEnabled);
2024-11-10 23:28:25 +01:00
2026-03-08 11:22:41 +01:00
public void Receive(NavigateManageAccountsRequested message) => SelectedMenuItemIndex = 0;
2025-01-01 17:28:29 +01:00
2026-02-13 03:09:13 +01:00
public void Receive(CalendarDisplayTypeChangedMessage message)
{
OnPropertyChanged(nameof(IsVerticalCalendar));
UpdateDateNavigationHeaderItems();
}
public async void Receive(AccountRemovedMessage message)
2026-03-07 01:46:07 +01:00
{
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;
}
2026-03-06 17:46:38 +01:00
private static (DateTime StartDate, DateTime EndDate) GetDefaultComposeDateRange()
{
var localNow = DateTime.Now;
var roundedMinutes = localNow.Minute switch
{
< 30 => 30,
30 when localNow.Second == 0 && localNow.Millisecond == 0 => 30,
_ => 60
};
var startDate = new DateTime(localNow.Year, localNow.Month, localNow.Day, localNow.Hour, 0, 0);
startDate = roundedMinutes == 60 ? startDate.AddHours(1) : startDate.AddMinutes(roundedMinutes);
return (startDate, startDate.AddMinutes(30));
}
2024-11-10 23:28:25 +01:00
}
2026-03-08 11:22:41 +01:00