Reminders.
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using CommunityToolkit.Mvvm.Messaging;
|
using CommunityToolkit.Mvvm.Messaging;
|
||||||
using Wino.Core.Domain.Interfaces;
|
using Wino.Core.Domain.Interfaces;
|
||||||
@@ -35,13 +36,22 @@ public partial class CalendarSettingsPageViewModel : CalendarBaseViewModel
|
|||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
public partial int WorkingDayEndIndex { get; set; }
|
public partial int WorkingDayEndIndex { get; set; }
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
public partial List<string> ReminderOptions { get; set; } = [];
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
public partial int SelectedDefaultReminderIndex { get; set; }
|
||||||
|
|
||||||
public IPreferencesService PreferencesService { get; }
|
public IPreferencesService PreferencesService { get; }
|
||||||
|
private readonly ICalendarService _calendarService;
|
||||||
|
|
||||||
private readonly bool _isLoaded = false;
|
private readonly bool _isLoaded = false;
|
||||||
|
|
||||||
public CalendarSettingsPageViewModel(IPreferencesService preferencesService)
|
public CalendarSettingsPageViewModel(IPreferencesService preferencesService, ICalendarService calendarService)
|
||||||
{
|
{
|
||||||
PreferencesService = preferencesService;
|
PreferencesService = preferencesService;
|
||||||
|
_calendarService = calendarService;
|
||||||
|
|
||||||
var currentLanguageLanguageCode = WinoTranslationDictionary.GetLanguageFileNameRelativePath(preferencesService.CurrentLanguage);
|
var currentLanguageLanguageCode = WinoTranslationDictionary.GetLanguageFileNameRelativePath(preferencesService.CurrentLanguage);
|
||||||
|
|
||||||
@@ -62,6 +72,31 @@ public partial class CalendarSettingsPageViewModel : CalendarBaseViewModel
|
|||||||
WorkingDayStartIndex = DayNames.IndexOf(cultureInfo.DateTimeFormat.GetDayName(preferencesService.WorkingDayStart));
|
WorkingDayStartIndex = DayNames.IndexOf(cultureInfo.DateTimeFormat.GetDayName(preferencesService.WorkingDayStart));
|
||||||
WorkingDayEndIndex = DayNames.IndexOf(cultureInfo.DateTimeFormat.GetDayName(preferencesService.WorkingDayEnd));
|
WorkingDayEndIndex = DayNames.IndexOf(cultureInfo.DateTimeFormat.GetDayName(preferencesService.WorkingDayEnd));
|
||||||
|
|
||||||
|
// Initialize reminder options
|
||||||
|
var predefinedMinutes = _calendarService.GetPredefinedReminderMinutes();
|
||||||
|
ReminderOptions.Add("None");
|
||||||
|
foreach (var minutes in predefinedMinutes)
|
||||||
|
{
|
||||||
|
var displayText = minutes switch
|
||||||
|
{
|
||||||
|
>= 60 => $"{minutes / 60} Hour{(minutes / 60 > 1 ? "s" : "")}",
|
||||||
|
_ => $"{minutes} Minute{(minutes > 1 ? "s" : "")}"
|
||||||
|
};
|
||||||
|
ReminderOptions.Add(displayText);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set selected index based on current default reminder setting
|
||||||
|
if (preferencesService.DefaultReminderDurationInSeconds == 0)
|
||||||
|
{
|
||||||
|
SelectedDefaultReminderIndex = 0; // None
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var minutes = (int)(preferencesService.DefaultReminderDurationInSeconds / 60);
|
||||||
|
var index = Array.IndexOf(predefinedMinutes, minutes);
|
||||||
|
SelectedDefaultReminderIndex = index >= 0 ? index + 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
_isLoaded = true;
|
_isLoaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,6 +107,7 @@ public partial class CalendarSettingsPageViewModel : CalendarBaseViewModel
|
|||||||
partial void OnWorkingHourEndChanged(TimeSpan value) => SaveSettings();
|
partial void OnWorkingHourEndChanged(TimeSpan value) => SaveSettings();
|
||||||
partial void OnWorkingDayStartIndexChanged(int value) => SaveSettings();
|
partial void OnWorkingDayStartIndexChanged(int value) => SaveSettings();
|
||||||
partial void OnWorkingDayEndIndexChanged(int value) => SaveSettings();
|
partial void OnWorkingDayEndIndexChanged(int value) => SaveSettings();
|
||||||
|
partial void OnSelectedDefaultReminderIndexChanged(int value) => SaveSettings();
|
||||||
|
|
||||||
public void SaveSettings()
|
public void SaveSettings()
|
||||||
{
|
{
|
||||||
@@ -118,6 +154,18 @@ public partial class CalendarSettingsPageViewModel : CalendarBaseViewModel
|
|||||||
PreferencesService.WorkingHourEnd = WorkingHourEnd;
|
PreferencesService.WorkingHourEnd = WorkingHourEnd;
|
||||||
PreferencesService.HourHeight = CellHourHeight;
|
PreferencesService.HourHeight = CellHourHeight;
|
||||||
|
|
||||||
|
// Save default reminder setting
|
||||||
|
if (SelectedDefaultReminderIndex == 0)
|
||||||
|
{
|
||||||
|
PreferencesService.DefaultReminderDurationInSeconds = 0; // None
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var predefinedMinutes = _calendarService.GetPredefinedReminderMinutes();
|
||||||
|
var minutes = predefinedMinutes[SelectedDefaultReminderIndex - 1];
|
||||||
|
PreferencesService.DefaultReminderDurationInSeconds = minutes * 60;
|
||||||
|
}
|
||||||
|
|
||||||
Messenger.Send(new CalendarSettingsUpdatedMessage());
|
Messenger.Send(new CalendarSettingsUpdatedMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using CommunityToolkit.Mvvm.Input;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
using CommunityToolkit.Mvvm.Messaging;
|
using CommunityToolkit.Mvvm.Messaging;
|
||||||
using Wino.Calendar.ViewModels.Data;
|
using Wino.Calendar.ViewModels.Data;
|
||||||
using Wino.Core.Domain;
|
using Wino.Core.Domain;
|
||||||
|
using Wino.Core.Domain.Entities.Calendar;
|
||||||
using Wino.Core.Domain.Enums;
|
using Wino.Core.Domain.Enums;
|
||||||
using Wino.Core.Domain.Interfaces;
|
using Wino.Core.Domain.Interfaces;
|
||||||
using Wino.Core.Domain.Models.Calendar;
|
using Wino.Core.Domain.Models.Calendar;
|
||||||
@@ -32,10 +35,14 @@ public partial class EventDetailsPageViewModel : CalendarBaseViewModel
|
|||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
[NotifyPropertyChangedFor(nameof(CanViewSeries))]
|
[NotifyPropertyChangedFor(nameof(CanViewSeries))]
|
||||||
[NotifyPropertyChangedFor(nameof(CanEditSeries))]
|
[NotifyPropertyChangedFor(nameof(CanEditSeries))]
|
||||||
private CalendarItemViewModel _currentEvent;
|
[NotifyPropertyChangedFor(nameof(IsCurrentUserOrganizer))]
|
||||||
|
public partial CalendarItemViewModel CurrentEvent { get; set; }
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private CalendarItemViewModel _seriesParent;
|
public partial CalendarItemViewModel SeriesParent { get; set; }
|
||||||
|
[ObservableProperty]
|
||||||
|
public partial List<Reminder> Reminders { get; set; }
|
||||||
|
|
||||||
|
public ObservableCollection<ReminderOption> ReminderOptions { get; } = new ObservableCollection<ReminderOption>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns true if the event is part of a recurring series (as a child occurrence).
|
/// Returns true if the event is part of a recurring series (as a child occurrence).
|
||||||
@@ -49,6 +56,12 @@ public partial class EventDetailsPageViewModel : CalendarBaseViewModel
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool CanEditSeries => CurrentEvent?.IsRecurringChild ?? false;
|
public bool CanEditSeries => CurrentEvent?.IsRecurringChild ?? false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns true if the current user is the organizer of the event.
|
||||||
|
/// Used to determine if the user can invite attendees or modify the event.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsCurrentUserOrganizer => CurrentEvent?.Attendees?.Any(a => a.IsOrganizer) ?? true;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Show As Options
|
#region Show As Options
|
||||||
@@ -113,6 +126,10 @@ public partial class EventDetailsPageViewModel : CalendarBaseViewModel
|
|||||||
{
|
{
|
||||||
CurrentEvent.Attendees.Add(item);
|
CurrentEvent.Attendees.Add(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load reminders for this calendar item
|
||||||
|
Reminders = await _calendarService.GetRemindersAsync(currentEventItem.EventTrackingId);
|
||||||
|
InitializeReminderOptions();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -120,17 +137,88 @@ public partial class EventDetailsPageViewModel : CalendarBaseViewModel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnNavigatedFrom(NavigationMode mode, object parameters)
|
private void InitializeReminderOptions()
|
||||||
{
|
{
|
||||||
base.OnNavigatedFrom(mode, parameters);
|
ReminderOptions.Clear();
|
||||||
|
|
||||||
Messenger.Send(new DetailsPageStateChangedMessage(false));
|
// Add predefined options from service
|
||||||
|
var predefinedMinutes = _calendarService.GetPredefinedReminderMinutes();
|
||||||
|
var predefinedOptions = predefinedMinutes.Select(m => new ReminderOption(m)).ToList();
|
||||||
|
|
||||||
|
// Add custom reminders from synced data
|
||||||
|
if (Reminders != null)
|
||||||
|
{
|
||||||
|
foreach (var reminder in Reminders)
|
||||||
|
{
|
||||||
|
// Convert seconds to minutes
|
||||||
|
var minutesDiff = (int)(reminder.DurationInSeconds / 60);
|
||||||
|
|
||||||
|
// Check if this is a custom value not in predefined list
|
||||||
|
if (!predefinedMinutes.Contains(minutesDiff))
|
||||||
|
{
|
||||||
|
predefinedOptions.Add(new ReminderOption(minutesDiff, isCustom: true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort by minutes descending and add to collection
|
||||||
|
foreach (var option in predefinedOptions.OrderByDescending(o => o.Minutes))
|
||||||
|
{
|
||||||
|
ReminderOptions.Add(option);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set selected state based on current reminders
|
||||||
|
if (Reminders != null)
|
||||||
|
{
|
||||||
|
foreach (var reminder in Reminders)
|
||||||
|
{
|
||||||
|
// Convert seconds to minutes
|
||||||
|
var minutesDiff = (int)(reminder.DurationInSeconds / 60);
|
||||||
|
|
||||||
|
var matchingOption = ReminderOptions.FirstOrDefault(o => o.Minutes == minutesDiff);
|
||||||
|
matchingOption?.IsSelected = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
private async Task SaveAsync()
|
private async Task SaveAsync()
|
||||||
{
|
{
|
||||||
// TODO: Implement saving
|
if (CurrentEvent == null) return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Get selected reminder options
|
||||||
|
var selectedOptions = ReminderOptions.Where(o => o.IsSelected).ToList();
|
||||||
|
|
||||||
|
// Create separate Reminder entities for each selected option
|
||||||
|
var newReminders = new List<Reminder>();
|
||||||
|
|
||||||
|
foreach (var option in selectedOptions)
|
||||||
|
{
|
||||||
|
var durationInSeconds = option.Minutes * 60; // Convert minutes to seconds
|
||||||
|
|
||||||
|
newReminders.Add(new Reminder
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
CalendarItemId = CurrentEvent.Id,
|
||||||
|
DurationInSeconds = durationInSeconds,
|
||||||
|
ReminderType = CalendarItemReminderType.Popup
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save reminders to database
|
||||||
|
await _calendarService.SaveRemindersAsync(CurrentEvent.CalendarItem.EventTrackingId, newReminders);
|
||||||
|
Reminders = newReminders;
|
||||||
|
|
||||||
|
_navigationService.GoBack();
|
||||||
|
// TODO: Implement saving other event details
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Debug.WriteLine($"Error saving event: {ex.Message}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
@@ -183,4 +271,55 @@ public partial class EventDetailsPageViewModel : CalendarBaseViewModel
|
|||||||
|
|
||||||
// TODO: Implement response
|
// TODO: Implement response
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private async Task ViewSeriesAsync()
|
||||||
|
{
|
||||||
|
if (CurrentEvent == null || !CurrentEvent.IsRecurringChild) return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Get the master event from the recurring series
|
||||||
|
var masterEventId = CurrentEvent.CalendarItem.RecurringCalendarItemId.Value;
|
||||||
|
var masterEvent = await _calendarService.GetCalendarItemAsync(masterEventId);
|
||||||
|
|
||||||
|
if (masterEvent == null) return;
|
||||||
|
|
||||||
|
// Load the master event without navigation
|
||||||
|
var target = new CalendarItemTarget(masterEvent, CalendarEventTargetType.Series);
|
||||||
|
await LoadCalendarItemTargetAsync(target);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Debug.WriteLine($"Error loading series: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public partial class ReminderOption : ObservableObject
|
||||||
|
{
|
||||||
|
public int Minutes { get; }
|
||||||
|
public bool IsCustom { get; }
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
public partial bool IsSelected { get; set; }
|
||||||
|
|
||||||
|
public string DisplayText
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (Minutes >= 60)
|
||||||
|
{
|
||||||
|
var hours = Minutes / 60;
|
||||||
|
return hours == 1 ? "1 Hour" : $"{hours} Hours";
|
||||||
|
}
|
||||||
|
return Minutes == 1 ? "1 Minute" : $"{Minutes} Minutes";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReminderOption(int minutes, bool isCustom = false)
|
||||||
|
{
|
||||||
|
Minutes = minutes;
|
||||||
|
IsCustom = isCustom;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,10 @@ public class Reminder
|
|||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
public Guid CalendarItemId { get; set; }
|
public Guid CalendarItemId { get; set; }
|
||||||
|
|
||||||
public DateTimeOffset ReminderTime { get; set; }
|
/// <summary>
|
||||||
|
/// Duration in seconds before the event start time when the reminder should trigger.
|
||||||
|
/// For example, 900 seconds = 15 minutes before event.
|
||||||
|
/// </summary>
|
||||||
|
public long DurationInSeconds { get; set; }
|
||||||
public CalendarItemReminderType ReminderType { get; set; }
|
public CalendarItemReminderType ReminderType { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,4 +47,11 @@ public interface ICalendarService
|
|||||||
Task<List<CalendarEventAttendee>> GetAttendeesAsync(Guid calendarEventTrackingId);
|
Task<List<CalendarEventAttendee>> GetAttendeesAsync(Guid calendarEventTrackingId);
|
||||||
Task<List<CalendarEventAttendee>> ManageEventAttendeesAsync(Guid calendarItemId, List<CalendarEventAttendee> allAttendees);
|
Task<List<CalendarEventAttendee>> ManageEventAttendeesAsync(Guid calendarItemId, List<CalendarEventAttendee> allAttendees);
|
||||||
Task UpdateCalendarItemAsync(CalendarItem calendarItem, List<CalendarEventAttendee> attendees);
|
Task UpdateCalendarItemAsync(CalendarItem calendarItem, List<CalendarEventAttendee> attendees);
|
||||||
|
Task<List<Reminder>> GetRemindersAsync(Guid calendarItemId);
|
||||||
|
Task SaveRemindersAsync(Guid calendarItemId, List<Reminder> reminders);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets predefined reminder options in minutes (1 Hour, 30 Min, 15 Min, 5 Min, 1 Min).
|
||||||
|
/// </summary>
|
||||||
|
int[] GetPredefinedReminderMinutes();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -216,6 +216,11 @@ public interface IPreferencesService : INotifyPropertyChanged
|
|||||||
DayOfWeek WorkingDayEnd { get; set; }
|
DayOfWeek WorkingDayEnd { get; set; }
|
||||||
double HourHeight { get; set; }
|
double HourHeight { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Setting: Default reminder duration in seconds for new calendar events.
|
||||||
|
/// Set to 0 to disable default reminders.
|
||||||
|
/// </summary>
|
||||||
|
long DefaultReminderDurationInSeconds { get; set; }
|
||||||
|
|
||||||
CalendarSettings GetCurrentCalendarSettings();
|
CalendarSettings GetCurrentCalendarSettings();
|
||||||
|
|
||||||
|
|||||||
@@ -223,7 +223,37 @@ public class GmailChangeProcessor : DefaultChangeProcessor, IGmailChangeProcesso
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prepare reminders list from Gmail event
|
||||||
|
List<Reminder> reminders = null;
|
||||||
|
if (calendarEvent.Reminders?.Overrides != null && calendarEvent.Reminders.Overrides.Count > 0)
|
||||||
|
{
|
||||||
|
reminders = new List<Reminder>();
|
||||||
|
foreach (var reminderOverride in calendarEvent.Reminders.Overrides)
|
||||||
|
{
|
||||||
|
if (reminderOverride.Minutes.HasValue)
|
||||||
|
{
|
||||||
|
var durationInSeconds = reminderOverride.Minutes.Value * 60; // Convert minutes to seconds
|
||||||
|
var reminderType = reminderOverride.Method switch
|
||||||
|
{
|
||||||
|
"email" => CalendarItemReminderType.Email,
|
||||||
|
_ => CalendarItemReminderType.Popup
|
||||||
|
};
|
||||||
|
|
||||||
|
reminders.Add(new Reminder
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
CalendarItemId = calendarItem.Id,
|
||||||
|
DurationInSeconds = durationInSeconds,
|
||||||
|
ReminderType = reminderType
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
await CalendarService.CreateNewCalendarItemAsync(calendarItem, attendees);
|
await CalendarService.CreateNewCalendarItemAsync(calendarItem, attendees);
|
||||||
|
|
||||||
|
// Save reminders separately
|
||||||
|
await CalendarService.SaveRemindersAsync(calendarItem.Id, reminders).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -255,6 +285,36 @@ public class GmailChangeProcessor : DefaultChangeProcessor, IGmailChangeProcesso
|
|||||||
|
|
||||||
// Update the event properties.
|
// Update the event properties.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prepare reminders list from Gmail event for update
|
||||||
|
List<Reminder> reminders = null;
|
||||||
|
if (calendarEvent.Reminders?.Overrides != null && calendarEvent.Reminders.Overrides.Count > 0)
|
||||||
|
{
|
||||||
|
reminders = new List<Reminder>();
|
||||||
|
foreach (var reminderOverride in calendarEvent.Reminders.Overrides)
|
||||||
|
{
|
||||||
|
if (reminderOverride.Minutes.HasValue)
|
||||||
|
{
|
||||||
|
var durationInSeconds = reminderOverride.Minutes.Value * 60; // Convert minutes to seconds
|
||||||
|
var reminderType = reminderOverride.Method switch
|
||||||
|
{
|
||||||
|
"email" => CalendarItemReminderType.Email,
|
||||||
|
_ => CalendarItemReminderType.Popup
|
||||||
|
};
|
||||||
|
|
||||||
|
reminders.Add(new Reminder
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
CalendarItemId = existingCalendarItem.Id,
|
||||||
|
DurationInSeconds = durationInSeconds,
|
||||||
|
ReminderType = reminderType
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save reminders
|
||||||
|
await CalendarService.SaveRemindersAsync(existingCalendarItem.Id, reminders).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Upsert the event.
|
// Upsert the event.
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ using Wino.Core.Domain.Enums;
|
|||||||
using Wino.Core.Domain.Interfaces;
|
using Wino.Core.Domain.Interfaces;
|
||||||
using Wino.Core.Extensions;
|
using Wino.Core.Extensions;
|
||||||
using Wino.Services;
|
using Wino.Services;
|
||||||
|
using Reminder = Wino.Core.Domain.Entities.Calendar.Reminder;
|
||||||
|
|
||||||
namespace Wino.Core.Integration.Processors;
|
namespace Wino.Core.Integration.Processors;
|
||||||
|
|
||||||
@@ -175,6 +176,25 @@ public class OutlookChangeProcessor(IDatabaseService databaseService,
|
|||||||
attendees = calendarEvent.Attendees.Select(a => a.CreateAttendee(savingItemId, organizerEmail)).ToList();
|
attendees = calendarEvent.Attendees.Select(a => a.CreateAttendee(savingItemId, organizerEmail)).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prepare reminders list from Outlook event
|
||||||
|
List<Reminder> reminders = null;
|
||||||
|
if (calendarEvent.IsReminderOn.GetValueOrDefault() && calendarEvent.ReminderMinutesBeforeStart.HasValue)
|
||||||
|
{
|
||||||
|
var reminderMinutes = calendarEvent.ReminderMinutesBeforeStart.Value;
|
||||||
|
var reminderDurationInSeconds = reminderMinutes * 60; // Convert minutes to seconds
|
||||||
|
|
||||||
|
reminders = new List<Reminder>
|
||||||
|
{
|
||||||
|
new Reminder
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
CalendarItemId = savingItemId,
|
||||||
|
DurationInSeconds = reminderDurationInSeconds,
|
||||||
|
ReminderType = CalendarItemReminderType.Popup
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Use CalendarService to create or update the event
|
// Use CalendarService to create or update the event
|
||||||
if (isNewItem)
|
if (isNewItem)
|
||||||
{
|
{
|
||||||
@@ -186,5 +206,8 @@ public class OutlookChangeProcessor(IDatabaseService databaseService,
|
|||||||
// Existing item - use UpdateCalendarItemAsync
|
// Existing item - use UpdateCalendarItemAsync
|
||||||
await CalendarService.UpdateCalendarItemAsync(savingItem, attendees).ConfigureAwait(false);
|
await CalendarService.UpdateCalendarItemAsync(savingItem, attendees).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Save reminders separately
|
||||||
|
await CalendarService.SaveRemindersAsync(savingItemId, reminders).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ public static class CalendarXamlHelpers
|
|||||||
|
|
||||||
public static string GetRecurrenceString(CalendarItemViewModel calendarItemViewModel)
|
public static string GetRecurrenceString(CalendarItemViewModel calendarItemViewModel)
|
||||||
{
|
{
|
||||||
|
// TODO: This is incorrect.
|
||||||
if (calendarItemViewModel == null || string.IsNullOrEmpty(calendarItemViewModel.CalendarItem.Recurrence)) return string.Empty;
|
if (calendarItemViewModel == null || string.IsNullOrEmpty(calendarItemViewModel.CalendarItem.Recurrence)) return string.Empty;
|
||||||
|
|
||||||
// Parse recurrence rules
|
// Parse recurrence rules
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ public class PreDefinedAppTheme : AppThemeBase
|
|||||||
|
|
||||||
public override async Task<string> GetThemeResourceDictionaryContentAsync()
|
public override async Task<string> GetThemeResourceDictionaryContentAsync()
|
||||||
{
|
{
|
||||||
var xamlDictionaryFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri($"ms-appx:///Wino.Mail.WinUI/AppThemes/{ThemeName}.xaml"));
|
var xamlDictionaryFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri($"ms-appx://AppThemes/{ThemeName}.xaml"));
|
||||||
return await FileIO.ReadTextAsync(xamlDictionaryFile);
|
return await FileIO.ReadTextAsync(xamlDictionaryFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -284,6 +284,12 @@ public class PreferencesService(IConfigurationService configurationService) : Ob
|
|||||||
set => SaveProperty(propertyName: nameof(WorkingDayEnd), value);
|
set => SaveProperty(propertyName: nameof(WorkingDayEnd), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long DefaultReminderDurationInSeconds
|
||||||
|
{
|
||||||
|
get => _configurationService.Get(nameof(DefaultReminderDurationInSeconds), 900L); // Default: 15 minutes (900 seconds)
|
||||||
|
set => SaveProperty(propertyName: nameof(DefaultReminderDurationInSeconds), value);
|
||||||
|
}
|
||||||
|
|
||||||
public int EmailSyncIntervalMinutes
|
public int EmailSyncIntervalMinutes
|
||||||
{
|
{
|
||||||
get => _configurationService.Get(nameof(EmailSyncIntervalMinutes), 3);
|
get => _configurationService.Get(nameof(EmailSyncIntervalMinutes), 3);
|
||||||
|
|||||||
@@ -178,6 +178,16 @@
|
|||||||
</controls:SettingsCard>
|
</controls:SettingsCard>
|
||||||
</controls:SettingsExpander.Items>
|
</controls:SettingsExpander.Items>
|
||||||
</controls:SettingsExpander>
|
</controls:SettingsExpander>
|
||||||
|
|
||||||
|
<!-- Default reminder -->
|
||||||
|
<controls:SettingsCard Description="Set a default reminder for all new calendar events." Header="Default reminder">
|
||||||
|
<controls:SettingsCard.HeaderIcon>
|
||||||
|
<PathIcon Data="F1 M 10 1.25 C 10.456706 1.25 10.889486 1.337565 11.298339 1.512695 C 11.707192 1.687826 12.072591 1.927409 12.394531 2.231445 C 12.716471 2.535482 12.97656 2.892253 13.173828 3.301758 C 13.371096 3.711263 13.481771 4.146484 13.505859 4.607422 L 13.505859 5 C 13.969401 5.028646 14.386068 5.16276 14.755859 5.402344 C 15.125651 5.641927 15.414713 5.947917 15.623047 6.320312 C 15.83138 6.692709 15.9349 7.096355 15.933594 7.53125 L 15.933594 8.75 L 16.25 8.75 C 16.822917 8.75 17.317057 8.95638 17.732422 9.369141 C 18.147787 9.781901 18.357422 10.273437 18.359375 10.84375 L 18.359375 16.40625 C 18.359375 16.979167 18.153971 17.473308 17.743164 17.888672 C 17.332357 18.304037 16.839844 18.511719 16.265625 18.511719 L 3.734375 18.511719 C 3.164062 18.511719 2.671549 18.304037 2.256836 17.888672 C 1.842122 17.473308 1.634114 16.979167 1.630859 16.40625 L 1.630859 10.84375 C 1.630859 10.273437 1.837565 9.781901 2.250977 9.369141 C 2.664388 8.95638 3.156901 8.75 3.728516 8.75 L 4.0625 8.75 L 4.0625 7.53125 C 4.0625 7.09375 4.166341 6.689453 4.374023 6.314453 C 4.581706 5.939453 4.86914 5.632486 5.236328 5.393555 C 5.603516 5.154623 6.019532 5.021485 6.484375 4.994141 L 6.484375 4.607422 C 6.506511 4.148438 6.617838 3.714518 6.818359 3.305664 C 7.01888 2.896811 7.282877 2.539063 7.610352 2.232422 C 7.937826 1.92578 8.308268 1.685222 8.721679 1.510742 C 9.135091 1.336264 9.56575 1.249024 10.013672 1.249024 Z M 10.013672 2.5 C 9.441406 2.5 8.947916 2.706381 8.533203 3.119141 C 8.118489 3.531901 7.911459 4.023437 7.912109 4.59375 L 7.912109 6.25 L 12.089844 6.25 L 12.089844 4.59375 C 12.089844 4.023438 11.882161 3.531902 11.466797 3.119141 C 11.051433 2.706382 10.557292 2.5 9.984375 2.5 Z M 5.3125 7.53125 L 5.3125 8.75 L 14.6875 8.75 L 14.6875 7.53125 C 14.6875 7.303385 14.605144 7.107747 14.440429 6.944336 C 14.275714 6.780925 14.080729 6.69987 13.855469 6.703125 L 6.142578 6.703125 C 5.914713 6.703125 5.71875 6.785482 5.552734 6.950195 C 5.386719 7.114909 5.30339 7.310547 5.300781 7.537109 Z M 16.25 10 L 3.75 10 C 3.540365 10 3.361328 10.071615 3.212891 10.214844 C 3.064453 10.358073 2.989258 10.534505 2.986328 10.744141 L 2.986328 16.40625 C 2.986328 16.618489 3.058595 16.797526 3.203125 16.943359 C 3.347656 17.089193 3.526693 17.161458 3.740234 17.15625 L 16.25 17.15625 C 16.458333 17.15625 16.636067 17.082683 16.783203 16.935547 C 16.930339 16.788411 17.003906 16.609375 17.003906 16.398437 L 17.003906 10.742187 C 17.003906 10.536459 16.932942 10.359049 16.791016 10.209961 C 16.64909 10.060873 16.469401 9.986328 16.257812 9.986328 Z M 10 11.5625 C 10.227865 11.5625 10.423502 11.644856 10.586914 11.809571 C 10.750325 11.974285 10.83138 12.16862 10.830078 12.393555 L 10.830078 13.427734 L 11.855469 13.427734 C 12.080404 13.427734 12.273437 13.509115 12.434571 13.671875 C 12.595704 13.834636 12.675781 14.026693 12.675781 14.248047 C 12.675781 14.46224 12.596354 14.653321 12.4375 14.813477 C 12.278646 14.973633 12.089192 15.053711 11.869141 15.053711 L 10.830078 15.053711 L 10.830078 16.074219 C 10.830078 16.296224 10.748372 16.486981 10.584961 16.646484 C 10.42155 16.805989 10.229818 16.885742 10.005859 16.885742 C 9.781901 16.885742 9.590495 16.806315 9.431641 16.647461 C 9.272786 16.488607 9.193359 16.296875 9.193359 16.072266 L 9.193359 15.053711 L 8.15625 15.053711 C 7.931314 15.053711 7.738934 14.972331 7.579102 14.80957 C 7.419269 14.646809 7.339192 14.454753 7.338867 14.233399 C 7.338867 14.008464 7.419921 13.815755 7.582031 13.655274 C 7.744141 13.494793 7.935872 13.414551 8.157227 13.414551 L 9.193359 13.414551 L 9.193359 12.394531 C 9.193359 12.166667 9.275715 11.971029 9.440429 11.807618 C 9.605144 11.644206 9.799479 11.562825 10.023437 11.5625 Z" />
|
||||||
|
</controls:SettingsCard.HeaderIcon>
|
||||||
|
<controls:SettingsCard.Content>
|
||||||
|
<ComboBox ItemsSource="{x:Bind ViewModel.ReminderOptions, Mode=OneWay}" SelectedIndex="{x:Bind ViewModel.SelectedDefaultReminderIndex, Mode=TwoWay}" />
|
||||||
|
</controls:SettingsCard.Content>
|
||||||
|
</controls:SettingsCard>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<VisualStateManager.VisualStateGroups>
|
<VisualStateManager.VisualStateGroups>
|
||||||
<VisualStateGroup x:Name="ClockIdentifierStates">
|
<VisualStateGroup x:Name="ClockIdentifierStates">
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
xmlns:abstract="using:Wino.Mail.WinUI.Views.Abstract"
|
xmlns:abstract="using:Wino.Mail.WinUI.Views.Abstract"
|
||||||
xmlns:calendar="using:Wino.Core.Domain.Entities.Calendar"
|
xmlns:calendar="using:Wino.Core.Domain.Entities.Calendar"
|
||||||
xmlns:calendarHelpers="using:Wino.Calendar.Helpers"
|
xmlns:calendarHelpers="using:Wino.Calendar.Helpers"
|
||||||
|
xmlns:calendarViewModels="using:Wino.Calendar.ViewModels"
|
||||||
xmlns:coreControls="using:Wino.Mail.WinUI.Controls"
|
xmlns:coreControls="using:Wino.Mail.WinUI.Controls"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:domain="using:Wino.Core.Domain"
|
xmlns:domain="using:Wino.Core.Domain"
|
||||||
@@ -29,8 +30,10 @@
|
|||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
<Style x:Key="EventDetailsPanelGridStyle" TargetType="Grid">
|
<Style x:Key="EventDetailsPanelGridStyle" TargetType="Grid">
|
||||||
<Setter Property="Padding" Value="0,12" />
|
<Setter Property="Padding" Value="12,6" />
|
||||||
<Setter Property="Margin" Value="12,0" />
|
<Setter Property="Margin" Value="0,12" />
|
||||||
|
<Setter Property="Background" Value="{ThemeResource CardBackgroundFillColorSecondaryBrush}" />
|
||||||
|
<Setter Property="CornerRadius" Value="{StaticResource ControlCornerRadius}" />
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
<Style
|
<Style
|
||||||
@@ -133,17 +136,38 @@
|
|||||||
|
|
||||||
<!-- Reminder -->
|
<!-- Reminder -->
|
||||||
<AppBarElementContainer>
|
<AppBarElementContainer>
|
||||||
<StackPanel Style="{StaticResource ActionBarElementContainerStackStyle}">
|
<Button>
|
||||||
<coreControls:WinoFontIcon FontSize="16" Icon="Reminder" />
|
<Button.Content>
|
||||||
<TextBlock VerticalAlignment="Center" Text="{x:Bind domain:Translator.CalendarEventDetails_Reminder}" />
|
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||||
<ComboBox Width="150" />
|
<coreControls:WinoFontIcon FontSize="16" Icon="Reminder" />
|
||||||
</StackPanel>
|
<TextBlock VerticalAlignment="Center" Text="{x:Bind domain:Translator.CalendarEventDetails_Reminder}" />
|
||||||
|
</StackPanel>
|
||||||
|
</Button.Content>
|
||||||
|
<Button.Flyout>
|
||||||
|
<Flyout>
|
||||||
|
<ListView
|
||||||
|
Width="200"
|
||||||
|
MaxHeight="300"
|
||||||
|
ItemsSource="{x:Bind ViewModel.ReminderOptions}"
|
||||||
|
SelectionMode="None">
|
||||||
|
<ListView.ItemTemplate>
|
||||||
|
<DataTemplate x:DataType="calendarViewModels:ReminderOption">
|
||||||
|
<CheckBox Content="{x:Bind DisplayText}" IsChecked="{x:Bind IsSelected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
|
||||||
|
</DataTemplate>
|
||||||
|
</ListView.ItemTemplate>
|
||||||
|
</ListView>
|
||||||
|
</Flyout>
|
||||||
|
</Button.Flyout>
|
||||||
|
</Button>
|
||||||
</AppBarElementContainer>
|
</AppBarElementContainer>
|
||||||
|
|
||||||
<AppBarSeparator />
|
<AppBarSeparator Visibility="{x:Bind ViewModel.CanEditSeries, Mode=OneWay}" />
|
||||||
|
|
||||||
<!-- Edit Series -->
|
<!-- Edit Series -->
|
||||||
<AppBarButton Label="{x:Bind domain:Translator.CalendarEventDetails_EditSeries}" Visibility="{x:Bind ViewModel.CanEditSeries, Mode=OneWay}">
|
<AppBarButton
|
||||||
|
Command="{x:Bind ViewModel.ViewSeriesCommand}"
|
||||||
|
Label="{x:Bind domain:Translator.CalendarEventDetails_EditSeries}"
|
||||||
|
Visibility="{x:Bind ViewModel.CanEditSeries, Mode=OneWay}">
|
||||||
<AppBarButton.Icon>
|
<AppBarButton.Icon>
|
||||||
<coreControls:WinoFontIcon Icon="EventEditSeries" />
|
<coreControls:WinoFontIcon Icon="EventEditSeries" />
|
||||||
</AppBarButton.Icon>
|
</AppBarButton.Icon>
|
||||||
@@ -153,7 +177,7 @@
|
|||||||
|
|
||||||
<!-- Event details -->
|
<!-- Event details -->
|
||||||
<ScrollViewer Grid.Row="1">
|
<ScrollViewer Grid.Row="1">
|
||||||
<Grid>
|
<Grid ColumnSpacing="8">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="2*" />
|
<ColumnDefinition Width="2*" />
|
||||||
<ColumnDefinition Width="1*" />
|
<ColumnDefinition Width="1*" />
|
||||||
@@ -204,7 +228,7 @@
|
|||||||
<Grid
|
<Grid
|
||||||
Grid.Row="3"
|
Grid.Row="3"
|
||||||
ColumnSpacing="6"
|
ColumnSpacing="6"
|
||||||
Visibility="{x:Bind ViewModel.CurrentEvent.IsRecurringParent}">
|
Visibility="{x:Bind ViewModel.CurrentEvent.IsRecurringParent, Mode=OneWay}">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="Auto" />
|
<ColumnDefinition Width="Auto" />
|
||||||
<ColumnDefinition Width="*" />
|
<ColumnDefinition Width="*" />
|
||||||
@@ -239,7 +263,7 @@
|
|||||||
|
|
||||||
<TextBlock Style="{StaticResource EventDetailsPanelTitleStyle}" Text="{x:Bind domain:Translator.CalendarEventDetails_People}" />
|
<TextBlock Style="{StaticResource EventDetailsPanelTitleStyle}" Text="{x:Bind domain:Translator.CalendarEventDetails_People}" />
|
||||||
|
|
||||||
<Grid Grid.Row="1" RowSpacing="12">
|
<Grid Grid.Row="1" RowSpacing="6">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="*" />
|
<RowDefinition Height="*" />
|
||||||
@@ -247,10 +271,12 @@
|
|||||||
<AutoSuggestBox
|
<AutoSuggestBox
|
||||||
Margin="6,0"
|
Margin="6,0"
|
||||||
BorderThickness="0"
|
BorderThickness="0"
|
||||||
PlaceholderText="{x:Bind domain:Translator.CalendarEventDetails_InviteSomeone}" />
|
PlaceholderText="{x:Bind domain:Translator.CalendarEventDetails_InviteSomeone}"
|
||||||
|
Visibility="{x:Bind ViewModel.IsCurrentUserOrganizer, Mode=OneWay}" />
|
||||||
|
|
||||||
<ListView
|
<ListView
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
|
Margin="-12,0"
|
||||||
IsItemClickEnabled="True"
|
IsItemClickEnabled="True"
|
||||||
ItemsSource="{x:Bind ViewModel.CurrentEvent.Attendees, Mode=OneWay}"
|
ItemsSource="{x:Bind ViewModel.CurrentEvent.Attendees, Mode=OneWay}"
|
||||||
SelectionMode="None">
|
SelectionMode="None">
|
||||||
|
|||||||
@@ -88,6 +88,13 @@
|
|||||||
<Content Remove="Assets\Wide310x150Logo.scale-400.png" />
|
<Content Remove="Assets\Wide310x150Logo.scale-400.png" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<None Remove="BackgroundImages\Acrylic.jpg" />
|
||||||
|
<None Remove="BackgroundImages\Clouds.jpg" />
|
||||||
|
<None Remove="BackgroundImages\Forest.jpg" />
|
||||||
|
<None Remove="BackgroundImages\Garden.jpg" />
|
||||||
|
<None Remove="BackgroundImages\Mica.jpg" />
|
||||||
|
<None Remove="BackgroundImages\Nighty.jpg" />
|
||||||
|
<None Remove="BackgroundImages\Snowflake.jpg" />
|
||||||
<None Remove="Controls\ListView\WinoListViewStyles.xaml" />
|
<None Remove="Controls\ListView\WinoListViewStyles.xaml" />
|
||||||
<None Remove="ShellWindow.xaml" />
|
<None Remove="ShellWindow.xaml" />
|
||||||
<None Remove="Styles\CalendarThemeResources.xaml" />
|
<None Remove="Styles\CalendarThemeResources.xaml" />
|
||||||
@@ -102,10 +109,37 @@
|
|||||||
<None Remove="Views\Calendar\EventDetailsPage.xaml" />
|
<None Remove="Views\Calendar\EventDetailsPage.xaml" />
|
||||||
<None Remove="Views\Settings\ContactsPage.xaml" />
|
<None Remove="Views\Settings\ContactsPage.xaml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Page Remove="AppThemes\Acrylic.xaml" />
|
||||||
|
<Page Remove="AppThemes\Clouds.xaml" />
|
||||||
|
<Page Remove="AppThemes\Custom.xaml" />
|
||||||
|
<Page Remove="AppThemes\Default.xaml" />
|
||||||
|
<Page Remove="AppThemes\Forest.xaml" />
|
||||||
|
<Page Remove="AppThemes\Garden.xaml" />
|
||||||
|
<Page Remove="AppThemes\Nighty.xaml" />
|
||||||
|
<Page Remove="AppThemes\Snowflake.xaml" />
|
||||||
|
<Page Remove="AppThemes\TestTheme.xaml" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Content Include="AppThemes\Acrylic.xaml" />
|
||||||
|
<Content Include="AppThemes\Clouds.xaml" />
|
||||||
|
<Content Include="AppThemes\Custom.xaml" />
|
||||||
|
<Content Include="AppThemes\Default.xaml" />
|
||||||
|
<Content Include="AppThemes\Forest.xaml" />
|
||||||
|
<Content Include="AppThemes\Garden.xaml" />
|
||||||
|
<Content Include="AppThemes\Nighty.xaml" />
|
||||||
|
<Content Include="AppThemes\Snowflake.xaml" />
|
||||||
|
<Content Include="AppThemes\TestTheme.xaml" />
|
||||||
<Content Include="Assets\LockScreenLogo.scale-200.png" />
|
<Content Include="Assets\LockScreenLogo.scale-200.png" />
|
||||||
<Content Include="Assets\Wino_Icon.ico" />
|
<Content Include="Assets\Wino_Icon.ico" />
|
||||||
|
<Content Include="BackgroundImages\Acrylic.jpg" />
|
||||||
|
<Content Include="BackgroundImages\Clouds.jpg" />
|
||||||
|
<Content Include="BackgroundImages\Forest.jpg" />
|
||||||
|
<Content Include="BackgroundImages\Garden.jpg" />
|
||||||
|
<Content Include="BackgroundImages\Mica.jpg" />
|
||||||
|
<Content Include="BackgroundImages\Nighty.jpg" />
|
||||||
|
<Content Include="BackgroundImages\Snowflake.jpg" />
|
||||||
<Content Include="JS\editor.html" />
|
<Content Include="JS\editor.html" />
|
||||||
<Content Include="JS\editor.js" />
|
<Content Include="JS\editor.js" />
|
||||||
<Content Include="JS\global.css" />
|
<Content Include="JS\global.css" />
|
||||||
|
|||||||
@@ -20,10 +20,15 @@ namespace Wino.Services;
|
|||||||
|
|
||||||
public class CalendarService : BaseDatabaseService, ICalendarService
|
public class CalendarService : BaseDatabaseService, ICalendarService
|
||||||
{
|
{
|
||||||
|
// Predefined reminder options in minutes
|
||||||
|
private static readonly int[] PredefinedReminderMinutes = [60, 30, 15, 5, 1];
|
||||||
|
|
||||||
public CalendarService(IDatabaseService databaseService) : base(databaseService)
|
public CalendarService(IDatabaseService databaseService) : base(databaseService)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int[] GetPredefinedReminderMinutes() => PredefinedReminderMinutes;
|
||||||
|
|
||||||
public Task<List<AccountCalendar>> GetAccountCalendarsAsync(Guid accountId)
|
public Task<List<AccountCalendar>> GetAccountCalendarsAsync(Guid accountId)
|
||||||
=> Connection.Table<AccountCalendar>().Where(x => x.AccountId == accountId).OrderByDescending(a => a.IsPrimary).ToListAsync();
|
=> Connection.Table<AccountCalendar>().Where(x => x.AccountId == accountId).OrderByDescending(a => a.IsPrimary).ToListAsync();
|
||||||
|
|
||||||
@@ -344,6 +349,10 @@ public class CalendarService : BaseDatabaseService, ICalendarService
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets attendees for a calendar item. For recurring event occurrences,
|
||||||
|
/// callers should pass the EventTrackingId which returns the parent's ID.
|
||||||
|
/// </summary>
|
||||||
public Task<List<CalendarEventAttendee>> GetAttendeesAsync(Guid calendarEventTrackingId)
|
public Task<List<CalendarEventAttendee>> GetAttendeesAsync(Guid calendarEventTrackingId)
|
||||||
=> Connection.Table<CalendarEventAttendee>().Where(x => x.CalendarItemId == calendarEventTrackingId).ToListAsync();
|
=> Connection.Table<CalendarEventAttendee>().Where(x => x.CalendarItemId == calendarEventTrackingId).ToListAsync();
|
||||||
|
|
||||||
@@ -423,4 +432,28 @@ public class CalendarService : BaseDatabaseService, ICalendarService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets reminders for a calendar item. For recurring event occurrences,
|
||||||
|
/// callers should pass the EventTrackingId which returns the parent's ID.
|
||||||
|
/// </summary>
|
||||||
|
public Task<List<Reminder>> GetRemindersAsync(Guid calendarItemId)
|
||||||
|
=> Connection.Table<Reminder>().Where(r => r.CalendarItemId == calendarItemId).ToListAsync();
|
||||||
|
|
||||||
|
public async Task SaveRemindersAsync(Guid calendarItemId, List<Reminder> reminders)
|
||||||
|
{
|
||||||
|
await Connection.RunInTransactionAsync((connection) =>
|
||||||
|
{
|
||||||
|
// Clear existing reminders for this calendar item
|
||||||
|
connection.Execute(
|
||||||
|
"DELETE FROM Reminder WHERE CalendarItemId = ?",
|
||||||
|
calendarItemId);
|
||||||
|
|
||||||
|
// Insert new reminders if any
|
||||||
|
if (reminders != null && reminders.Count > 0)
|
||||||
|
{
|
||||||
|
connection.InsertAll(reminders, typeof(Reminder));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user