diff --git a/src/Unlimotion.ViewModel/DurationFilter.cs b/src/Unlimotion.ViewModel/DurationFilter.cs new file mode 100644 index 0000000..b736b32 --- /dev/null +++ b/src/Unlimotion.ViewModel/DurationFilter.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.ObjectModel; +using DynamicData.Binding; +using PropertyChanged; + +namespace Unlimotion.ViewModel; + +[AddINotifyPropertyChangedInterface] +public class DurationFilter +{ + public string Title { get; set; } + public bool ShowTasks { get; set; } + public Func Predicate { get; set; } + + public static ReadOnlyObservableCollection GetDefinitions() + { + return new ReadOnlyObservableCollection(new ObservableCollectionExtended + { + new() + { + Title = "No duration", + Predicate = e => e.PlannedDuration == null + }, + new() + { + Title = "<=5m", + Predicate = e => e.PlannedDuration <= TimeSpan.FromMinutes(5) + }, + new() + { + Title = "5m< & <=30m", + Predicate = e => TimeSpan.FromMinutes(5) < e.PlannedDuration && e.PlannedDuration <= TimeSpan.FromMinutes(30) + }, + new() + { + Title = "30m< & <=2h", + Predicate = e => TimeSpan.FromMinutes(30) < e.PlannedDuration && e.PlannedDuration <= TimeSpan.FromHours(2) + }, + new() + { + Title = "2h< & <=1d", + Predicate = e => TimeSpan.FromHours(2) < e.PlannedDuration && e.PlannedDuration <= TimeSpan.FromDays(1) + }, + new() + { + Title = "1d<", + Predicate = e => TimeSpan.FromDays(1) < e.PlannedDuration + } + }); + } +} \ No newline at end of file diff --git a/src/Unlimotion.ViewModel/MainWindowViewModel.cs b/src/Unlimotion.ViewModel/MainWindowViewModel.cs index eae1004..d826a9c 100644 --- a/src/Unlimotion.ViewModel/MainWindowViewModel.cs +++ b/src/Unlimotion.ViewModel/MainWindowViewModel.cs @@ -342,6 +342,20 @@ bool Predicate(TaskItemViewModel task) return (Func)Predicate; }); + + var durationFilter = DurationFilters.ToObservableChangeSet() + .AutoRefreshOnObservable(filter => filter.WhenAnyValue(e => e.ShowTasks)) + .ToCollection() + .Select(filter => + { + bool Predicate(TaskItemViewModel task) + { + return (filter.All(e => e.ShowTasks == false) || + filter.Where(e => e.ShowTasks).Any(item => item.Predicate(task))); + } + + return (Func)Predicate; + }); this.WhenAnyValue(m => m.ArchivedDateFilter.CurrentOption, m => m.ArchivedDateFilter.IsCustom) .Subscribe(filter => @@ -443,6 +457,7 @@ bool Predicate(TaskItemViewModel task) m => m.PlannedDuration, m => m.PlannedEndDateTime)) .Filter(unlockedTimeFilter) + .Filter(durationFilter) .Filter(emojiFilter) .Filter(wantedFilter) .Transform(item => @@ -947,6 +962,7 @@ public TaskWrapperViewModel FindTaskWrapperViewModel(TaskItemViewModel taskItemV public EmojiFilter AllEmojiFilter { get; } = new() { Emoji = "", Title = "All", ShowTasks = false, SortText = "\u0000" }; public ReadOnlyObservableCollection UnlockedTimeFilters { get; set; } = UnlockedTimeFilter.GetDefinitions(); + public ReadOnlyObservableCollection DurationFilters { get; set; } = DurationFilter.GetDefinitions(); public bool DetailsAreOpen { get; set; } public DateFilter CompletedDateFilter { get; set; } = new(); diff --git a/src/Unlimotion.ViewModel/SetDurationCommands.cs b/src/Unlimotion.ViewModel/SetDurationCommands.cs new file mode 100644 index 0000000..d1b3e1e --- /dev/null +++ b/src/Unlimotion.ViewModel/SetDurationCommands.cs @@ -0,0 +1,47 @@ +using System; +using System.Windows.Input; +using PropertyChanged; +using ReactiveUI; + +namespace Unlimotion.ViewModel; + +[AddINotifyPropertyChangedInterface] +public class SetDurationCommands +{ + TaskItemViewModel taskItemViewModel; + + public SetDurationCommands(TaskItemViewModel item) + { + taskItemViewModel = item; + var hasDuration = taskItemViewModel.WhenAny(m => m.PlannedDuration, (time) => time.Value != null); + var any = taskItemViewModel.WhenAny(m => m.PlannedDuration, (time) => true); + + OneMinCommand = ReactiveCommand.Create(() => taskItemViewModel.PlannedDuration = TimeSpan.FromMinutes(1), any); + FiveMinutesCommand = ReactiveCommand.Create(() => taskItemViewModel.PlannedDuration = TimeSpan.FromMinutes(5), any); + TenMinutesCommand = ReactiveCommand.Create(() => taskItemViewModel.PlannedDuration = TimeSpan.FromMinutes(10), any); + TwentyMinutesCommand = ReactiveCommand.Create(() => taskItemViewModel.PlannedDuration = TimeSpan.FromMinutes(20), any); + FortyMinutesCommand = ReactiveCommand.Create(() => taskItemViewModel.PlannedDuration = TimeSpan.FromMinutes(40), any); + OneHourCommand = ReactiveCommand.Create(() => taskItemViewModel.PlannedDuration = TimeSpan.FromHours(1), any); + TwoHoursCommand = ReactiveCommand.Create(() => taskItemViewModel.PlannedDuration = TimeSpan.FromHours(2), any); + FourHoursCommand = ReactiveCommand.Create(() => taskItemViewModel.PlannedDuration = TimeSpan.FromHours(4), any); + OneDayCommand = ReactiveCommand.Create(() => taskItemViewModel.PlannedDuration = TimeSpan.FromDays(1), any); + TwoDaysCommand = ReactiveCommand.Create(() => taskItemViewModel.PlannedDuration = TimeSpan.FromDays(2), any); + FourDaysCommand = ReactiveCommand.Create(() => taskItemViewModel.PlannedDuration = TimeSpan.FromDays(4), any); + EightDaysCommand = ReactiveCommand.Create(() => taskItemViewModel.PlannedDuration = TimeSpan.FromDays(8), any); + NoneCommand = ReactiveCommand.Create(() => taskItemViewModel.PlannedDuration = null, hasDuration); + } + + public ICommand OneMinCommand { get; set; } + public ICommand FiveMinutesCommand { get; set; } + public ICommand TenMinutesCommand { get; set; } + public ICommand TwentyMinutesCommand { get; set; } + public ICommand FortyMinutesCommand { get; set; } + public ICommand OneHourCommand { get; set; } + public ICommand TwoHoursCommand { get; set; } + public ICommand FourHoursCommand { get; set; } + public ICommand OneDayCommand { get; set; } + public ICommand TwoDaysCommand { get; set; } + public ICommand FourDaysCommand { get; set; } + public ICommand EightDaysCommand { get; set; } + public ICommand NoneCommand { get; set; } +} \ No newline at end of file diff --git a/src/Unlimotion.ViewModel/TaskItemViewModel.cs b/src/Unlimotion.ViewModel/TaskItemViewModel.cs index 6036d7e..9288df7 100644 --- a/src/Unlimotion.ViewModel/TaskItemViewModel.cs +++ b/src/Unlimotion.ViewModel/TaskItemViewModel.cs @@ -39,9 +39,11 @@ private bool GetCanBeCompleted() => (ContainsTasks.All(m => m.IsCompleted != fal private ReadOnlyObservableCollection _blockedByTasks; private TimeSpan? plannedPeriod; private DateCommands commands = null; + public SetDurationCommands SetDurationCommands { get; set; } private void Init(ITaskRepository taskRepository) { + SetDurationCommands = new SetDurationCommands(this); SaveItemCommand = ReactiveCommand.CreateFromTask(async () => { var model = Model; @@ -722,7 +724,7 @@ public IEnumerable GetAllParents() /// Команды для быстрого выбора дат, ленивая загрузка /// public DateCommands Commands => commands ??= new DateCommands(this); - + private void ShowModalAndChangeChildrenStatuses(INotificationManagerWrapper notificationManager, string taskName, List childrenTasks, ArchiveMethodType methodType) { diff --git a/src/Unlimotion/Views/MainControl.axaml b/src/Unlimotion/Views/MainControl.axaml index 51a84d8..18504cf 100644 --- a/src/Unlimotion/Views/MainControl.axaml +++ b/src/Unlimotion/Views/MainControl.axaml @@ -1,16 +1,16 @@ +x:Class="Unlimotion.Views.MainControl"> @@ -31,10 +31,10 @@