using System.Reactive.Linq; using System.Reactive.Subjects; using FileTime.Core.Models; namespace FileTime.Core.Services { public class Tab : ITab { private readonly BehaviorSubject _currentLocation = new(null); private readonly BehaviorSubject _currentSelectedItem = new(null); private readonly List _transformators = new(); private IAbsolutePath? _currentSelectedItemCached; public IObservable CurrentLocation { get; } public IObservable> CurrentItems { get; } public IObservable CurrentSelectedItem { get; } public Tab() { CurrentLocation = _currentLocation.DistinctUntilChanged().Do(_ => {; }).Publish(null).RefCount(); CurrentItems = Observable.Merge( CurrentLocation .Where(c => c is not null) .Select(c => c!.Items) .Switch() .Select(i => Observable.FromAsync(async () => await MapItems(i))) .Switch(), CurrentLocation .Where(c => c is null) .Select(_ => Enumerable.Empty()) ) .Publish(Enumerable.Empty()) .RefCount(); CurrentSelectedItem = CurrentLocation .Select(GetSelectedItemByLocation) .Switch() .Merge(_currentSelectedItem) .DistinctUntilChanged() .Publish(null) .RefCount(); CurrentSelectedItem.Subscribe(s => { _currentSelectedItemCached = s; _currentSelectedItem.OnNext(s); }); } private async Task> MapItems(IReadOnlyList items) { IEnumerable resolvedItems = await items .ToAsyncEnumerable() .SelectAwait( async i => { try { //TODO: force create by AbsolutePath name return await i.ContentProvider.GetItemByFullNameAsync(i.Path); } catch { return null!; } } ) .Where(i => i != null) .ToListAsync(); return _transformators.Count == 0 ? resolvedItems : (await _transformators .ToAsyncEnumerable() .Scan(resolvedItems, (acc, t) => new ValueTask>(t.Transformator(acc))) .ToListAsync() ) .SelectMany(t => t); } public void Init(IContainer currentLocation) { _currentLocation.OnNext(currentLocation); } private IObservable GetSelectedItemByLocation(IContainer? currentLocation) { //TODO: return currentLocation?.Items?.Select(i => i.FirstOrDefault()) ?? Observable.Never((IAbsolutePath?)null); } public void SetCurrentLocation(IContainer newLocation) => _currentLocation.OnNext(newLocation); public void SetSelectedItem(IAbsolutePath newSelectedItem) => _currentSelectedItem.OnNext(newSelectedItem); public void AddSelectedItemsTransformator(ItemsTransformator transformator) => _transformators.Add(transformator); public void RemoveSelectedItemsTransformator(ItemsTransformator transformator) => _transformators.Remove(transformator); public void RemoveSelectedItemsTransformatorByName(string name) => _transformators.RemoveAll(t => t.Name == name); public async Task OpenSelected() { if (_currentSelectedItemCached == null) return; var resolvedSelectedItem = await _currentSelectedItemCached.ContentProvider.GetItemByFullNameAsync(_currentSelectedItemCached.Path); if (resolvedSelectedItem is not IContainer resolvedContainer) return; SetCurrentLocation(resolvedContainer); } } }