private RepoTreeItem FilterByTagPrefix(ILoadedRepository repo, string prefix, Func <string, string> convertor)
        {
            // var nodes = new ObservableCollection<PackageCategoryTreeItem>();

            var map = new Dictionary <string, List <PackageMenuItem> >();

            foreach (var package in repo.Packages.Packages)
            {
                if (package.Value == null)
                {
                    continue;
                }

                IDescriptor descriptor = package.Value !;

                var pkgKey  = PackageKey.Create(repo.Index.Url, descriptor.Id);
                var release = repo.Release(pkgKey);
                var payload = release?.WindowsExecutable();

                if (release == null || payload == null)
                {
                    continue;
                }

                var tags = Iter.ToArray(descriptor.Tags.Where(x => x.StartsWith(prefix)));

                if (tags.IsNullOrEmpty())
                {
                    tags = new[] { prefix };
                }

                foreach (var tag in tags)
                {
                    if (!map.ContainsKey(tag))
                    {
                        map[tag] = new List <PackageMenuItem>();
                    }

                    map[tag].Add(new PackageMenuItem(_store,
                                                     pkgKey, payload, descriptor.NativeName() ?? "<>", release.Version));
                }
            }

            var categoriesSet = new SortedSet <PackageCategoryTreeItem>(map.OrderBy(x => x.Key).Map(x => {
                x.Value.Sort();
                var items = new ObservableCollection <PackageMenuItem>(x.Value);
                return(new PackageCategoryTreeItem(_store, convertor(x.Key), items));
            }));

            var categories = new ObservableCollection <PackageCategoryTreeItem>(categoriesSet);

            return(new RepoTreeItem(repo.Index.NativeName(), categories));
        }
        private IDisposable BindGroupToggled(IMainPageView view, UserPackageSelectionStore store)
        {
            return(view.OnGroupToggled()
                   .Subscribe(tree => {
                PahkatApp.Current.Dispatcher.InvokeAsync(async() => {
                    Log.Verbose("Toggle group");
                    var list = new List <PackageKey>();
                    foreach (var task in tree.Items.Map(x => x.Key.DefaultPackageAction()))
                    {
                        var v = await task;
                        list.Add(v.PackageKey);
                    }

                    await store.ToggleGroupWithDefaultAction(Iter.ToArray(list), !tree.IsGroupSelected);
                });
            }));
        }
        private IDisposable BindPrimaryButton(IMainPageView view)
        {
            return(view.OnPrimaryButtonPressed()
                   .Subscribe(_ => {
                Log.Verbose("Primary button pressed");
                var app = PahkatApp.Current;
                var actions = Iter.ToArray(_store.State.SelectedPackages.Values);

                Task.Run(async() => {
                    try {
                        await app.PackageStore.ProcessTransaction(actions, value => {
                            Log.Debug("-- New event: " + value);
                            var newState = app.CurrentTransaction.Value.Reduce(value);
                            app.CurrentTransaction.OnNext(newState);
                        });
                    }
                    catch (Exception e) {
                        _view.HandleError(e);
                    }
                });
            }));
        }