diff --git a/Wino.Calendar.ViewModels/AppShellViewModel.cs b/Wino.Calendar.ViewModels/AppShellViewModel.cs index c782bf9d..3a50ffd9 100644 --- a/Wino.Calendar.ViewModels/AppShellViewModel.cs +++ b/Wino.Calendar.ViewModels/AppShellViewModel.cs @@ -29,6 +29,8 @@ namespace Wino.Calendar.ViewModels IRecipient, IRecipient { + + public IPreferencesService PreferencesService { get; } public IStatePersistanceService StatePersistenceService { get; } public IAccountCalendarStateService AccountCalendarStateService { get; } @@ -65,6 +67,9 @@ namespace Wino.Calendar.ViewModels [ObservableProperty] private int _selectedDateNavigationHeaderIndex; + + + public bool IsVerticalCalendar => StatePersistenceService.CalendarDisplayType == CalendarDisplayType.Month; // For updating account calendars asynchronously. @@ -93,6 +98,11 @@ namespace Wino.Calendar.ViewModels StatePersistenceService.StatePropertyChanged += PrefefencesChanged; } + private void SelectedCalendarItemsChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) + { + throw new NotImplementedException(); + } + private void PrefefencesChanged(object sender, string e) { if (e == nameof(StatePersistenceService.CalendarDisplayType)) diff --git a/Wino.Calendar.ViewModels/CalendarPageViewModel.cs b/Wino.Calendar.ViewModels/CalendarPageViewModel.cs index f99deaad..978721c9 100644 --- a/Wino.Calendar.ViewModels/CalendarPageViewModel.cs +++ b/Wino.Calendar.ViewModels/CalendarPageViewModel.cs @@ -12,6 +12,7 @@ using MoreLinq; using Serilog; using Wino.Calendar.ViewModels.Data; using Wino.Calendar.ViewModels.Interfaces; +using Wino.Calendar.ViewModels.Messages; using Wino.Core.Domain.Collections; using Wino.Core.Domain.Entities.Calendar; using Wino.Core.Domain.Enums; @@ -26,7 +27,10 @@ namespace Wino.Calendar.ViewModels { public partial class CalendarPageViewModel : CalendarBaseViewModel, IRecipient, - IRecipient + IRecipient, + IRecipient, + IRecipient, + IRecipient { #region Quick Event Creation @@ -101,6 +105,7 @@ namespace Wino.Calendar.ViewModels private const int maxDayRangeSize = 10; private readonly ICalendarService _calendarService; + private readonly IKeyPressService _keyPressService; private readonly IPreferencesService _preferencesService; // Store latest rendered options. @@ -116,6 +121,7 @@ namespace Wino.Calendar.ViewModels public CalendarPageViewModel(IStatePersistanceService statePersistanceService, ICalendarService calendarService, + IKeyPressService keyPressService, IAccountCalendarStateService accountCalendarStateService, IPreferencesService preferencesService) { @@ -123,6 +129,7 @@ namespace Wino.Calendar.ViewModels AccountCalendarStateService = accountCalendarStateService; _calendarService = calendarService; + _keyPressService = keyPressService; _preferencesService = preferencesService; AccountCalendarStateService.AccountCalendarSelectionStateChanged += UpdateAccountCalendarRequested; @@ -179,7 +186,7 @@ namespace Wino.Calendar.ViewModels var testCalendarItem = new CalendarItem { - CalendarId = Guid.Parse("40aa0bf0-9ea7-40d8-b426-9c78281723c9"), + CalendarId = SelectedQuickEventAccountCalendar.Id, StartDate = QuickEventStartTime, DurationInSeconds = durationSeconds, CreatedAt = DateTime.UtcNow, @@ -522,10 +529,6 @@ namespace Wino.Calendar.ViewModels { base.OnCalendarItemAdded(calendarItem); - // test - var calendar = await _calendarService.GetAccountCalendarAsync(Guid.Parse("40aa0bf0-9ea7-40d8-b426-9c78281723c9")); - - calendarItem.AssignedCalendar = calendar; // Check if event falls into the current date range. var loadedDateRange = GetLoadedDateRange(); @@ -733,5 +736,72 @@ namespace Wino.Calendar.ViewModels // Messenger.Send(new LoadCalendarMessage(DateTime.UtcNow.Date, CalendarInitInitiative.App, true)); } + + private IEnumerable GetCalendarItems(Guid calendarItemId) + { + // Multi-day events are sprated in multiple days. + // We need to find the day that the event is in, and then select the event. + + return DayRanges + .SelectMany(a => a.CalendarDays) + .Select(b => b.EventsCollection.GetCalendarItem(calendarItemId)) + .Where(c => c != null) + .Cast() + .Distinct(); + } + + private void ResetSelectedItems() + { + foreach (var item in AccountCalendarStateService.SelectedItems) + { + var items = GetCalendarItems(item.Id); + + foreach (var childItem in items) + { + childItem.IsSelected = false; + } + } + + AccountCalendarStateService.SelectedItems.Clear(); + } + + public async void Receive(CalendarItemTappedMessage message) + { + if (message.CalendarItemViewModel == null) return; + + await ExecuteUIThread(() => + { + var calendarItems = GetCalendarItems(message.CalendarItemViewModel.Id); + + if (!_keyPressService.IsCtrlKeyPressed()) + { + ResetSelectedItems(); + } + + foreach (var item in calendarItems) + { + item.IsSelected = !item.IsSelected; + + // Multi-select logic. + if (item.IsSelected && !AccountCalendarStateService.SelectedItems.Contains(item)) + { + AccountCalendarStateService.SelectedItems.Add(message.CalendarItemViewModel); + } + else if (!item.IsSelected && AccountCalendarStateService.SelectedItems.Contains(item)) + { + AccountCalendarStateService.SelectedItems.Remove(item); + } + } + }); + } + + public void Receive(CalendarItemDoubleTappedMessage message) + { + // TODO: Navigate to the event details page. + } + + public void Receive(CalendarItemRightTappedMessage message) + { + } } } diff --git a/Wino.Calendar.ViewModels/Data/CalendarItemViewModel.cs b/Wino.Calendar.ViewModels/Data/CalendarItemViewModel.cs index d85be653..4621a935 100644 --- a/Wino.Calendar.ViewModels/Data/CalendarItemViewModel.cs +++ b/Wino.Calendar.ViewModels/Data/CalendarItemViewModel.cs @@ -28,6 +28,11 @@ namespace Wino.Calendar.ViewModels.Data public bool IsMultiDayEvent => ((ICalendarItem)CalendarItem).IsMultiDayEvent; + public bool IsRecurringEvent => !string.IsNullOrEmpty(CalendarItem.Recurrence); + + [ObservableProperty] + private bool _isSelected; + public CalendarItemViewModel(CalendarItem calendarItem) { CalendarItem = calendarItem; diff --git a/Wino.Calendar.ViewModels/Interfaces/IAccountCalendarStateService.cs b/Wino.Calendar.ViewModels/Interfaces/IAccountCalendarStateService.cs index bb4f60d5..2865ccd0 100644 --- a/Wino.Calendar.ViewModels/Interfaces/IAccountCalendarStateService.cs +++ b/Wino.Calendar.ViewModels/Interfaces/IAccountCalendarStateService.cs @@ -1,13 +1,14 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.ComponentModel; using System.Linq; using Wino.Calendar.ViewModels.Data; using Wino.Core.Domain.Entities.Shared; namespace Wino.Calendar.ViewModels.Interfaces { - public interface IAccountCalendarStateService + public interface IAccountCalendarStateService : INotifyPropertyChanged { ReadOnlyObservableCollection GroupedAccountCalendars { get; } @@ -21,6 +22,9 @@ namespace Wino.Calendar.ViewModels.Interfaces public void AddAccountCalendar(AccountCalendarViewModel accountCalendar); public void RemoveAccountCalendar(AccountCalendarViewModel accountCalendar); + ObservableCollection SelectedItems { get; } + bool HasMultipleSelectedItems { get; } + /// /// Enumeration of currently selected calendars. /// diff --git a/Wino.Calendar.ViewModels/Messages/CalendarItemDoubleTappedMessage.cs b/Wino.Calendar.ViewModels/Messages/CalendarItemDoubleTappedMessage.cs new file mode 100644 index 00000000..7898adb9 --- /dev/null +++ b/Wino.Calendar.ViewModels/Messages/CalendarItemDoubleTappedMessage.cs @@ -0,0 +1,14 @@ +using Wino.Calendar.ViewModels.Data; + +namespace Wino.Calendar.ViewModels.Messages +{ + public class CalendarItemDoubleTappedMessage + { + public CalendarItemDoubleTappedMessage(CalendarItemViewModel calendarItemViewModel) + { + CalendarItemViewModel = calendarItemViewModel; + } + + public CalendarItemViewModel CalendarItemViewModel { get; } + } +} diff --git a/Wino.Calendar.ViewModels/Messages/CalendarItemRightTappedMessage.cs b/Wino.Calendar.ViewModels/Messages/CalendarItemRightTappedMessage.cs new file mode 100644 index 00000000..9d4fe8e5 --- /dev/null +++ b/Wino.Calendar.ViewModels/Messages/CalendarItemRightTappedMessage.cs @@ -0,0 +1,14 @@ +using Wino.Calendar.ViewModels.Data; + +namespace Wino.Calendar.ViewModels.Messages +{ + public class CalendarItemRightTappedMessage + { + public CalendarItemRightTappedMessage(CalendarItemViewModel calendarItemViewModel) + { + CalendarItemViewModel = calendarItemViewModel; + } + + public CalendarItemViewModel CalendarItemViewModel { get; } + } +} diff --git a/Wino.Calendar.ViewModels/Messages/CalendarItemTappedMessage.cs b/Wino.Calendar.ViewModels/Messages/CalendarItemTappedMessage.cs new file mode 100644 index 00000000..edebe9ea --- /dev/null +++ b/Wino.Calendar.ViewModels/Messages/CalendarItemTappedMessage.cs @@ -0,0 +1,14 @@ +using Wino.Calendar.ViewModels.Data; + +namespace Wino.Calendar.ViewModels.Messages +{ + public class CalendarItemTappedMessage + { + public CalendarItemTappedMessage(CalendarItemViewModel calendarItemViewModel) + { + CalendarItemViewModel = calendarItemViewModel; + } + + public CalendarItemViewModel CalendarItemViewModel { get; } + } +} diff --git a/Wino.Calendar/Controls/AllDayItemsControl.xaml b/Wino.Calendar/Controls/AllDayItemsControl.xaml index 23586de3..32972cbd 100644 --- a/Wino.Calendar/Controls/AllDayItemsControl.xaml +++ b/Wino.Calendar/Controls/AllDayItemsControl.xaml @@ -2,6 +2,7 @@ x:Class="Wino.Calendar.Controls.AllDayItemsControl" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:calendarHelpers="using:Wino.Calendar.Helpers" xmlns:controls="using:Wino.Calendar.Controls" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:data="using:Wino.Calendar.ViewModels.Data" @@ -15,7 +16,7 @@