commits
tags
#include "torlinkc/ui/sort.hpp"
#include <algorithm>
namespace torlinkc::ui {
namespace {
bool sameSort(const Sort& a, const Sort& b) {
if (!a || !b) return !a && !b;
return a->field == b->field && a->dir == b->dir;
}
std::string fieldName(SortField f) {
switch (f) {
case SortField::Size:
return "size";
case SortField::Seeders:
return "seeders";
case SortField::Source:
return "source";
case SortField::Added:
return "added";
}
return "size";
}
} // namespace
const std::vector<Sort>& sortCycle() {
static const std::vector<Sort> cycle = {
std::nullopt,
SortState{SortField::Size, SortDir::Asc},
SortState{SortField::Size, SortDir::Desc},
SortState{SortField::Seeders, SortDir::Asc},
SortState{SortField::Seeders, SortDir::Desc},
SortState{SortField::Source, SortDir::Asc},
SortState{SortField::Source, SortDir::Desc},
SortState{SortField::Added, SortDir::Asc},
SortState{SortField::Added, SortDir::Desc},
};
return cycle;
}
Sort nextSort(const Sort& current) {
const auto& cycle = sortCycle();
auto it = std::find_if(cycle.begin(), cycle.end(), [&](const Sort& s) { return sameSort(s, current); });
const std::size_t i = it == cycle.end() ? 0 : static_cast<std::size_t>(it - cycle.begin());
return cycle[(i + 1) % cycle.size()];
}
std::string sortArrow(SortDir dir) { return dir == SortDir::Asc ? "▴" : "▾"; }
std::string sortLabel(const Sort& sort) {
if (!sort) return "default";
return fieldName(sort->field) + " " + sortArrow(sort->dir);
}
std::vector<TorrentResult> sortResults(const std::vector<TorrentResult>& list, const Sort& sort) {
std::vector<TorrentResult> arr = list;
if (!sort) return arr;
// `a` sorts before `b` exactly when this JS-style combined comparator
// value (mul * primary, falling through to a tiebreak) is negative --
// mirrors ui/sort.ts::sortResults's `mul * (...) || (...)` chains, just
// spelled out instead of relying on JS's truthy-`||` short-circuit.
const long long mul = sort->dir == SortDir::Asc ? 1 : -1;
switch (sort->field) {
case SortField::Size:
std::stable_sort(arr.begin(), arr.end(), [&](const TorrentResult& a, const TorrentResult& b) {
const long long primary = mul * (a.sizeBytes - b.sizeBytes);
return primary != 0 ? primary < 0 : (b.seeders - a.seeders) < 0;
});
break;
case SortField::Seeders:
std::stable_sort(arr.begin(), arr.end(), [&](const TorrentResult& a, const TorrentResult& b) {
const long long primary = mul * (a.seeders - b.seeders);
return primary != 0 ? primary < 0 : (b.added.value_or(0) - a.added.value_or(0)) < 0;
});
break;
case SortField::Source:
std::stable_sort(arr.begin(), arr.end(), [&](const TorrentResult& a, const TorrentResult& b) {
const long long primary = mul * a.source.compare(b.source);
return primary != 0 ? primary < 0 : (b.seeders - a.seeders) < 0;
});
break;
case SortField::Added:
std::stable_sort(arr.begin(), arr.end(), [&](const TorrentResult& a, const TorrentResult& b) {
const long long primary = mul * (a.added.value_or(0) - b.added.value_or(0));
return primary != 0 ? primary < 0 : (b.seeders - a.seeders) < 0;
});
break;
}
return arr;
}
} // namespace torlinkc::ui