using System.Collections.ObjectModel; using System.Reactive.Linq; using System.Reactive.Subjects; using DeclarativeProperty; using FileTime.App.Core.Configuration; using FileTime.App.Core.Models.Enums; using FileTime.Core.Models.Extensions; using MoreLinq; using PropertyChanged.SourceGenerator; namespace FileTime.App.Core.ViewModels; public abstract partial class AppStateBase : IAppState { private readonly BehaviorSubject _searchText = new(null); private readonly DeclarativeProperty _selectedTab = new(null); private readonly DeclarativeProperty _viewMode = new(Models.Enums.ViewMode.Default); private readonly ObservableCollection _tabs = new(); private readonly DeclarativeProperty _rapidTravelText; public IDeclarativeProperty ViewMode { get; } public ReadOnlyObservableCollection Tabs { get; } public IObservable SearchText { get; } public IDeclarativeProperty SelectedTab { get; } public IDeclarativeProperty RapidTravelText { get; } public IDeclarativeProperty RapidTravelTextDebounced { get; } public IDeclarativeProperty ContainerStatus { get; } [Notify] public List PreviousKeys { get; } = new(); [Notify] public bool NoCommandFound { get; set; } protected AppStateBase() { _rapidTravelText = new (""); RapidTravelText = _rapidTravelText.DistinctUntilChanged(); RapidTravelTextDebounced = RapidTravelText .Debounce(v => string.IsNullOrEmpty(v) ? TimeSpan.Zero : TimeSpan.FromMilliseconds(200) , resetTimer: true ); ViewMode = _viewMode; SearchText = _searchText.AsObservable(); SelectedTab = DeclarativePropertyHelpers.CombineLatest, ITabViewModel, ITabViewModel>( _tabs.Watch()!, _selectedTab!, (tabs, selectedTab) => Task.FromResult(GetSelectedTab(tabs, selectedTab)!) )!; Tabs = new ReadOnlyObservableCollection(_tabs); ContainerStatus = SelectedTab .Map(t => t?.CurrentLocation) .Switch() .Map(c => c?.GetExtension()?.GetStatusProperty()) .Switch()!; } public void AddTab(ITabViewModel tabViewModel) { if (_tabs.Any(t => t.TabNumber == tabViewModel.TabNumber)) throw new ArgumentException($"There is a tab with the same tab number {tabViewModel.TabNumber}.", nameof(tabViewModel)); var index = _tabs.Count(t => t.TabNumber < tabViewModel.TabNumber); _tabs.Insert(index, tabViewModel); } public void RemoveTab(ITabViewModel tabViewModel) { if (!_tabs.Contains(tabViewModel)) return; _tabs.Remove(tabViewModel); } public void SetSearchText(string? searchText) => _searchText.OnNext(searchText); public async Task SwitchViewModeAsync(ViewMode newViewMode) => await _viewMode.SetValue(newViewMode); public async Task SetSelectedTabAsync(ITabViewModel tabToSelect) => await _selectedTab.SetValue(tabToSelect); public async Task SetRapidTravelTextAsync(string? text) => await _rapidTravelText.SetValue(text); private ITabViewModel? GetSelectedTab(IEnumerable tabs, ITabViewModel? expectedSelectedTab) { var (preferred, others) = tabs .OrderBy(t => t.TabNumber) .Partition(t => t.TabNumber >= (expectedSelectedTab?.TabNumber ?? 0)); return preferred.Concat(others.Reverse()).FirstOrDefault(); } }