summaryrefslogtreecommitdiff
path: root/accounts/gkleen@sif/shell/quickshell-plugins/FileSelector.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'accounts/gkleen@sif/shell/quickshell-plugins/FileSelector.cpp')
-rw-r--r--accounts/gkleen@sif/shell/quickshell-plugins/FileSelector.cpp99
1 files changed, 99 insertions, 0 deletions
diff --git a/accounts/gkleen@sif/shell/quickshell-plugins/FileSelector.cpp b/accounts/gkleen@sif/shell/quickshell-plugins/FileSelector.cpp
new file mode 100644
index 00000000..3a0537b6
--- /dev/null
+++ b/accounts/gkleen@sif/shell/quickshell-plugins/FileSelector.cpp
@@ -0,0 +1,99 @@
1#include "FileSelector.hpp"
2
3#include <sstream>
4#include <vector>
5#include <random>
6#include <algorithm>
7
8#include <iostream>
9#include <format>
10
11namespace fs = std::filesystem;
12
13FileSelector::FileSelector(QObject* parent): QObject(parent) {
14 QObject::connect(&this->timer, &QTimer::timeout, this, &FileSelector::onTimeout);
15}
16
17QString FileSelector::directory() const {
18 return QString::fromStdString(this->mDirectory->string());
19}
20void FileSelector::setDirectory(QString directory) {
21 this->mDirectory = directory.toStdString();
22 if (this->mDirectory && this->mEpoch)
23 this->update();
24 emit this->directoryChanged();
25}
26
27unsigned int FileSelector::epoch() const {
28 return std::chrono::duration_cast<std::chrono::milliseconds>(*this->mEpoch).count();
29}
30void FileSelector::setEpoch(unsigned int epoch) {
31 this->mEpoch = std::chrono::milliseconds{epoch};
32 if (this->mDirectory && this->mEpoch)
33 this->update();
34 emit this->epochChanged();
35}
36
37QString FileSelector::seed() const {
38 return this->mSeed;
39}
40void FileSelector::setSeed(QString seed) {
41 this->mSeed = seed;
42 emit this->seedChanged();
43}
44
45QString FileSelector::selected() const {
46 if (!this->mDirectory || !this->mEpoch)
47 return QString();
48
49 std::vector<fs::path> shuffled(this->mFiles.begin(), this->mFiles.end());
50 std::sort(shuffled.begin(), shuffled.end());
51
52 auto currentTime = std::chrono::system_clock::now();
53 uint64_t currentEpoch = currentTime.time_since_epoch() / *this->mEpoch;
54 std::chrono::milliseconds timeInEpoch = std::chrono::duration_cast<std::chrono::milliseconds>(currentTime.time_since_epoch()) % *this->mEpoch;
55
56 std::ostringstream seed;
57 seed << this->mSeed.size() << ";" << this->mSeed.toStdString() << ";";
58 seed << *this->mEpoch << ";";
59 seed << currentEpoch << ";";
60 seed << this->mDirectory->string().size() << ";" << *this->mDirectory << ";";
61 seed << this->mFiles.size() << ";";
62 for (const fs::path& p: this->mFiles)
63 seed << p.string().size() << ";" << p << ";";
64
65 std::vector<std::seed_seq::result_type> v;
66 v.reserve(seed.str().size());
67 for (const char& c: seed.str())
68 v.push_back(c);
69
70 std::seed_seq engine_seed(v.begin(), v.end());
71 std::mt19937 g(engine_seed);
72 std::shuffle(shuffled.begin(), shuffled.end(), g);
73
74 std::vector<fs::path>::size_type ix = shuffled.size() * timeInEpoch / *this->mEpoch;
75 return QString::fromStdString((*this->mDirectory / shuffled[ix]).string());
76}
77
78void FileSelector::onTimeout() {
79 if (!this->mFiles.size())
80 return;
81
82 auto currentTime = std::chrono::system_clock::now();
83 uint64_t currentMinorEpoch = currentTime.time_since_epoch() / (*this->mEpoch / this->mFiles.size());
84 auto nextTime = std::chrono::time_point<std::chrono::system_clock>((2 * currentMinorEpoch + 3) * (*this->mEpoch / (this->mFiles.size() * 2)));
85 this->timer.start(std::chrono::duration_cast<std::chrono::milliseconds>(nextTime - currentTime).count());
86
87 emit this->selectedChanged();
88}
89
90void FileSelector::update() {
91 this->mFiles = std::set<fs::path>{};
92 for (const fs::directory_entry& entry:
93 fs::recursive_directory_iterator(*this->mDirectory, fs::directory_options::follow_directory_symlink))
94 {
95 this->mFiles.insert(fs::relative(entry, *this->mDirectory));
96 }
97
98 this->onTimeout();
99}