mirror of
https://github.com/jorenchik/mdemory.git
synced 2026-03-22 00:26:21 +00:00
spacing with correct cooldowns and updates
This commit is contained in:
14
src/include/main.h
Normal file
14
src/include/main.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "parser.h"
|
||||
|
||||
void update();
|
||||
void saveMdem();
|
||||
|
||||
struct MdemBuffer {
|
||||
std::vector<Question*> questions = std::vector<Question*>();
|
||||
time_t trainedAt = 0;
|
||||
};
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <QMainWindow>
|
||||
|
||||
#include "main.h"
|
||||
#include "parser.h"
|
||||
|
||||
extern QMainWindow *trainWindow;
|
||||
@@ -15,7 +16,6 @@ enum PracticeAlgorithm {
|
||||
void initTrainWindow();
|
||||
|
||||
void initiatePractice(
|
||||
std::vector<Question*> questions,
|
||||
PracticeAlgorithm algorithm,
|
||||
time_t *trainedAt
|
||||
MdemBuffer *mdemBuffer,
|
||||
PracticeAlgorithm algorithm
|
||||
);
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
#include <QPushButton>
|
||||
#include <QStandardPaths>
|
||||
|
||||
#include "main.h"
|
||||
#include "api.h"
|
||||
#include "parser.h"
|
||||
#include "qscilexer.h"
|
||||
@@ -86,11 +87,6 @@ struct Mdem {
|
||||
Question *question;
|
||||
};
|
||||
|
||||
struct MdemBuffer {
|
||||
std::vector<Question*> questions = std::vector<Question*>();
|
||||
time_t trainedAt = 0;
|
||||
};
|
||||
|
||||
struct ErrorView {
|
||||
QWidget box;
|
||||
QVBoxLayout layout;
|
||||
@@ -164,6 +160,8 @@ std::string outputMdem(std::vector<Question*> questions, time_t time = 0) {
|
||||
std::stringstream ss;
|
||||
|
||||
if (time > 0) {
|
||||
auto timezoneOffset = settings->value("timezone").toInt();
|
||||
/*time = time + 3600 * timezoneOffset;*/
|
||||
std::tm* tm = std::localtime(&time);
|
||||
char buffer[100];
|
||||
std::strftime(buffer, sizeof(buffer), "%d.%m.%Y %H\\:%M", tm);
|
||||
@@ -242,8 +240,13 @@ void makePages() {
|
||||
|
||||
void setupMdem(Mdem *mdem, Question *question) {
|
||||
if (MultiElementQuestion* mw = dynamic_cast<MultiElementQuestion*>(question)) {
|
||||
std::stringstream ss;
|
||||
if (mw->Cooldown > 0) {
|
||||
ss << std::format("[{:.2f}] ", question->Cooldown);
|
||||
}
|
||||
ss << mw->QuestionText;
|
||||
mdem->wFrontText.setText(
|
||||
QString::fromStdString(mw->QuestionText)
|
||||
QString::fromStdString(ss.str())
|
||||
);
|
||||
auto choices = mw->Choices;
|
||||
for (size_t k = 0; k < choices.size(); ++k) {
|
||||
@@ -444,7 +447,35 @@ void CreateMdems(std::vector<Question*>& questions) {
|
||||
hMdemScroll->addItem(mdemSpacer);
|
||||
}
|
||||
|
||||
void updateMdemInfo(std::string filename, bool isChanged = false) {
|
||||
if (filename.length() > 0) {
|
||||
std::stringstream ss;
|
||||
ss << std::format("mdem: {}", filename);
|
||||
if (isChanged) {
|
||||
ss << "*";
|
||||
}
|
||||
if (mdemBuffer->trainedAt > 0) {
|
||||
std::tm* tm = std::localtime(&mdemBuffer->trainedAt);
|
||||
char buffer[100];
|
||||
std::strftime(buffer, sizeof(buffer), "%d.%m.%Y %H:%M", tm);
|
||||
ss << std::endl << "Last practiced: " << std::string(buffer);
|
||||
}
|
||||
deckListLabel->setText(QString::fromStdString(ss.str()));
|
||||
} else {
|
||||
deckListLabel->setText("");
|
||||
}
|
||||
}
|
||||
|
||||
std::string getFilename(std::string path) {
|
||||
std::smatch matches;
|
||||
auto filenameMatched = std::regex_search(path, matches, lastPathElementExp);
|
||||
return matches[2].str();
|
||||
}
|
||||
|
||||
void update() {
|
||||
SwitchPage(currentPage);
|
||||
updateMdemInfo(getFilename(currentMdem));
|
||||
}
|
||||
|
||||
void SwitchPage(int pageIdx) {
|
||||
currentPage = pageIdx;
|
||||
@@ -560,29 +591,6 @@ void releaseError(ErrorView** item) {
|
||||
std::cout << std::format("Released, current pool size: {}\n", errorPool.size());
|
||||
}
|
||||
|
||||
std::string getFilename(std::string path) {
|
||||
std::smatch matches;
|
||||
auto filenameMatched = std::regex_search(path, matches, lastPathElementExp);
|
||||
return matches[2].str();
|
||||
}
|
||||
|
||||
|
||||
void updateMdemInfo(std::string filename) {
|
||||
if (filename.length() > 0) {
|
||||
std::stringstream ss;
|
||||
ss << std::format("mdem: {}", filename);
|
||||
if (mdemBuffer->trainedAt > 0) {
|
||||
std::tm* tm = std::localtime(&mdemBuffer->trainedAt);
|
||||
char buffer[100];
|
||||
std::strftime(buffer, sizeof(buffer), "%d.%m.%Y %H:%M", tm);
|
||||
ss << std::endl << "Last practiced: " << std::string(buffer);
|
||||
}
|
||||
deckListLabel->setText(QString::fromStdString(ss.str()));
|
||||
} else {
|
||||
deckListLabel->setText("");
|
||||
}
|
||||
}
|
||||
|
||||
void reloadMdem() {
|
||||
auto file = std::ifstream(currentMdem);
|
||||
std::string content;
|
||||
@@ -616,7 +624,7 @@ void reloadMdem() {
|
||||
mdemBuffer->trainedAt = 0;
|
||||
} else {
|
||||
auto timezoneOffset = settings->value("timezone").toInt();
|
||||
mdemBuffer->trainedAt = res.value.lastTrainedAt + 3600 * timezoneOffset;
|
||||
mdemBuffer->trainedAt = res.value.lastTrainedAt - 3600 * timezoneOffset;
|
||||
}
|
||||
std::cout << std::format("Last trained at: {}", mdemBuffer->trainedAt) << std::endl;
|
||||
|
||||
@@ -705,13 +713,13 @@ void setupEditorSave(bool checked) {
|
||||
for (int i = 0; i < mdemBuffer->questions.size(); ++i) {
|
||||
if (mdemBuffer->questions[i] == oldQuestion) {
|
||||
mdemBuffer->questions.erase(mdemBuffer->questions.begin() + i);
|
||||
delete mdemBuffer->questions[i];
|
||||
mdemBuffer->questions[i] = editMdem->question;
|
||||
delete oldQuestion;
|
||||
mdemBuffer->questions.insert(mdemBuffer->questions.begin() + i, res.value.questions[0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*setupMdem(editMdem, res.value.questions[0]);*/
|
||||
/*showBacklabels(editMdem);*/
|
||||
setupMdem(editMdem, res.value.questions[0]);
|
||||
showBacklabels(editMdem);
|
||||
editorWindow->hide();
|
||||
} else {
|
||||
QMessageBox::information(
|
||||
@@ -741,6 +749,12 @@ void setupEditorSave(bool checked) {
|
||||
}
|
||||
};
|
||||
|
||||
void saveMdem() {
|
||||
auto filename = getFilename(currentMdem);
|
||||
std::ofstream out(currentMdem);
|
||||
out << outputMdem(mdemBuffer->questions, mdemBuffer->trainedAt);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
mdemBuffer = new MdemBuffer;
|
||||
QApplication app(argc, argv);
|
||||
@@ -952,9 +966,9 @@ int main(int argc, char *argv[]) {
|
||||
hlButtonsTop->addWidget(add);
|
||||
hlButtonsTop->addWidget(save);
|
||||
hlButtonsTop->addWidget(load);
|
||||
cbAlgorithm->addItem("Primary", PRIMARY);
|
||||
cbAlgorithm->addItem("Random", RANDOM);
|
||||
cbAlgorithm->addItem("Spaced", SPACED);
|
||||
cbAlgorithm->addItem("Random", RANDOM);
|
||||
cbAlgorithm->addItem("Primary", PRIMARY);
|
||||
practice->setText("Practice");
|
||||
hlButtonsBottom->addWidget(cbAlgorithm);
|
||||
hlButtonsBottom->addWidget(practice);
|
||||
@@ -972,9 +986,7 @@ int main(int argc, char *argv[]) {
|
||||
});
|
||||
QObject::connect(load, &QToolButton::clicked, &reloadMdem);
|
||||
QObject::connect(save, &QToolButton::clicked, []() {
|
||||
auto filename = getFilename(currentMdem);
|
||||
std::ofstream out(currentMdem);
|
||||
out << outputMdem(mdemBuffer->questions, mdemBuffer->trainedAt);
|
||||
saveMdem();
|
||||
});
|
||||
QObject::connect(
|
||||
practice,
|
||||
@@ -983,9 +995,8 @@ int main(int argc, char *argv[]) {
|
||||
trainWindow->show();
|
||||
trainWindow->resize(600, 300);
|
||||
initiatePractice(
|
||||
mdemBuffer->questions,
|
||||
static_cast<PracticeAlgorithm>(cbAlgorithm->currentData().toInt()),
|
||||
&mdemBuffer->trainedAt
|
||||
mdemBuffer,
|
||||
static_cast<PracticeAlgorithm>(cbAlgorithm->currentData().toInt())
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
#include <QWidget>
|
||||
#include <QToolButton>
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
#include <ctime>
|
||||
#include <format>
|
||||
#include <cstdlib>
|
||||
#include <exception>
|
||||
#include <format>
|
||||
#include <qabstractitemview.h>
|
||||
#include <qboxlayout.h>
|
||||
#include <qchar.h>
|
||||
#include <qcoreevent.h>
|
||||
#include <qlabel.h>
|
||||
#include <qlayoutitem.h>
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <qnamespace.h>
|
||||
#include <qscrollarea.h>
|
||||
#include <qstandarditemmodel.h>
|
||||
#include <qstringalgorithms.h>
|
||||
#include <qstringlistmodel.h>
|
||||
#include <qtoolbutton.h>
|
||||
#include <Qt>
|
||||
@@ -29,6 +30,7 @@
|
||||
#include <QStyledItemDelegate>
|
||||
#include <QPainter>
|
||||
|
||||
#include "main.h"
|
||||
#include "trainWindow.h"
|
||||
#include "parser.h"
|
||||
|
||||
@@ -204,7 +206,6 @@ QLabel *lQuestionText;
|
||||
QVBoxLayout *vButtonBox;
|
||||
QWidget *actionButtons;
|
||||
QHBoxLayout *hButtons;
|
||||
QToolButton *btnPrev;
|
||||
QSpacerItem *leftSpacer;
|
||||
QToolButton *btnTriggerAnswer;
|
||||
QSpacerItem *rightSpacer;
|
||||
@@ -229,10 +230,12 @@ QVBoxLayout *vGroups;
|
||||
std::vector<QStandardItemModel*> groupModels;
|
||||
|
||||
// Questions & State
|
||||
std::vector<Question*> trainQuestions = std::vector<Question*>();
|
||||
MdemBuffer *currentBuffer;
|
||||
|
||||
int32_t currentQuestionIndex = -1;
|
||||
std::vector<GroupView*> groupViews;
|
||||
PracticeAlgorithm practiceAlgoritm;
|
||||
time_t lastTrainedAt;
|
||||
|
||||
std::default_random_engine rng;
|
||||
std::vector<QStandardItem*> itemPool;
|
||||
@@ -285,6 +288,11 @@ void hideQuestionElements() {
|
||||
orderList->hide();
|
||||
multiChoiceList->hide();
|
||||
wGroupQuestion->hide();
|
||||
btnNotRemembered->hide();
|
||||
btnHard->hide();
|
||||
btnMedium->hide();
|
||||
btnEasy->hide();
|
||||
btnTriggerAnswer->hide();
|
||||
}
|
||||
|
||||
void setupAnswerQuestion(MultiElementQuestion *question) {
|
||||
@@ -308,6 +316,10 @@ void setupAnswerQuestion(MultiElementQuestion *question) {
|
||||
[](bool checked) {
|
||||
answerText->show();
|
||||
btnTriggerAnswer->hide();
|
||||
btnNotRemembered->show();
|
||||
btnHard->show();
|
||||
btnMedium->show();
|
||||
btnEasy->show();
|
||||
}
|
||||
);
|
||||
btnTriggerAnswer->show();
|
||||
@@ -491,63 +503,132 @@ void setupQuestion(Question *question) {
|
||||
hideQuestionElements();
|
||||
releaseAllItems();
|
||||
QObject::disconnect(btnTriggerAnswer, 0, 0, 0);
|
||||
if (auto *question = dynamic_cast<MultiElementQuestion*>(trainQuestions[currentQuestionIndex])) {
|
||||
btnNotRemembered->hide();
|
||||
btnHard->hide();
|
||||
btnMedium->hide();
|
||||
btnEasy->hide();
|
||||
switch (question->type) {
|
||||
if (auto *q = dynamic_cast<MultiElementQuestion*>(question)) {
|
||||
switch (q->type) {
|
||||
case MultiElementType::Order:
|
||||
setupOrderQuestion(question);
|
||||
setupOrderQuestion(q);
|
||||
break;
|
||||
case MultiElementType::MultiChoice:
|
||||
setupMultiChoiceQuestion(question);
|
||||
setupMultiChoiceQuestion(q);
|
||||
break;
|
||||
case MultiElementType::Regular:
|
||||
setupAnswerQuestion(question);
|
||||
setupAnswerQuestion(q);
|
||||
break;
|
||||
}
|
||||
} else if (auto *question = dynamic_cast<GroupQuestion*>(trainQuestions[currentQuestionIndex])) {
|
||||
} else if (auto *question = dynamic_cast<GroupQuestion*>(
|
||||
currentBuffer->questions[currentQuestionIndex])
|
||||
) {
|
||||
setupGroupQuestion(question);
|
||||
}
|
||||
}
|
||||
|
||||
void updatePaginationVisibility() {
|
||||
if (currentQuestionIndex == 0) {
|
||||
btnPrev->hide();
|
||||
} else {
|
||||
btnPrev->show();
|
||||
}
|
||||
if (currentQuestionIndex == trainQuestions.size() - 1) {
|
||||
if (currentQuestionIndex == currentBuffer->questions.size() - 1) {
|
||||
btnNext->hide();
|
||||
} else {
|
||||
btnNext->show();
|
||||
}
|
||||
}
|
||||
|
||||
void initiatePractice(
|
||||
std::vector<Question*> questions,
|
||||
PracticeAlgorithm algorithm,
|
||||
time_t *trainedAt
|
||||
) {
|
||||
template <typename T>
|
||||
int randomIndex(std::vector<T> *vec) {
|
||||
srand(time(NULL));
|
||||
return rand() % vec->size();
|
||||
}
|
||||
|
||||
time_t getTime() {
|
||||
auto now = std::chrono::system_clock::now();
|
||||
time_t unix_timestamp = std::chrono::duration_cast<std::chrono::seconds>(
|
||||
return std::chrono::duration_cast<std::chrono::seconds>(
|
||||
now.time_since_epoch()
|
||||
).count();
|
||||
}
|
||||
|
||||
trainQuestions = questions;
|
||||
if (questions.size() <= 0) {
|
||||
void setupNextQuestion() {
|
||||
if (currentBuffer->questions.size() <= 0) {
|
||||
return;
|
||||
}
|
||||
currentQuestionIndex = 0;
|
||||
switch (practiceAlgoritm) {
|
||||
case PRIMARY: {
|
||||
currentQuestionIndex++;
|
||||
if (currentQuestionIndex < currentBuffer->questions.size()) {
|
||||
setupQuestion(currentBuffer->questions[currentQuestionIndex]);
|
||||
}
|
||||
updatePaginationVisibility();
|
||||
setupQuestion(trainQuestions[currentQuestionIndex]);
|
||||
practiceAlgoritm = algorithm;
|
||||
} break;
|
||||
case RANDOM: {
|
||||
auto questionCandidates = currentBuffer->questions;
|
||||
if (currentQuestionIndex > -1) {
|
||||
questionCandidates.erase(questionCandidates.begin() + currentQuestionIndex);
|
||||
}
|
||||
if (questionCandidates.size() > 0) {
|
||||
auto i = randomIndex(&questionCandidates);
|
||||
setupQuestion(questionCandidates[i]);
|
||||
for (int k = 0; k < currentBuffer->questions.size(); ++k) {
|
||||
if (currentBuffer->questions[k] == questionCandidates[i]) {
|
||||
currentQuestionIndex = k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case SPACED: {
|
||||
auto questionCandidates = std::vector<Question*>();
|
||||
time_t time = getTime();
|
||||
auto lastTrainedAt = currentBuffer->trainedAt;
|
||||
currentBuffer->trainedAt = time;
|
||||
for (int i = 0; i < currentBuffer->questions.size(); ++i) {
|
||||
auto cooldownSeconds = currentBuffer->questions[i]->Cooldown * 3600;
|
||||
auto cooldownEndsAt = lastTrainedAt + cooldownSeconds;
|
||||
if (i != currentQuestionIndex && cooldownEndsAt <= time) {
|
||||
questionCandidates.push_back(currentBuffer->questions[i]);
|
||||
}
|
||||
auto newCooldown = cooldownEndsAt - time;
|
||||
if (newCooldown < 0) {
|
||||
newCooldown = 0;
|
||||
}
|
||||
currentBuffer->questions[i]->Cooldown = (double)newCooldown / 3600;
|
||||
}
|
||||
if (questionCandidates.size() > 0) {
|
||||
auto i = randomIndex(&questionCandidates);
|
||||
setupQuestion(questionCandidates[i]);
|
||||
setupQuestion(
|
||||
questionCandidates[randomIndex(&questionCandidates)]
|
||||
);
|
||||
for (int k = 0; k < currentBuffer->questions.size(); ++k) {
|
||||
if (currentBuffer->questions[k] == questionCandidates[i]) {
|
||||
currentQuestionIndex = k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
update();
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
btnNotRemembered->hide();
|
||||
btnHard->hide();
|
||||
btnMedium->hide();
|
||||
btnEasy->hide();
|
||||
void initiatePractice(
|
||||
MdemBuffer *mdemBuffer,
|
||||
PracticeAlgorithm algorithm
|
||||
) {
|
||||
practiceAlgoritm = algorithm;
|
||||
currentBuffer = mdemBuffer;
|
||||
|
||||
if (currentBuffer->questions.size() <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
currentQuestionIndex = -1;
|
||||
hideQuestionElements();
|
||||
updatePaginationVisibility();
|
||||
setupNextQuestion();
|
||||
}
|
||||
|
||||
void setCooldownHours(int cooldown) {
|
||||
time_t time = getTime();
|
||||
currentBuffer->trainedAt = time;
|
||||
auto question = currentBuffer->questions[currentQuestionIndex];
|
||||
question->Cooldown = cooldown;
|
||||
update();
|
||||
}
|
||||
|
||||
void initTrainWindow() {
|
||||
@@ -566,6 +647,25 @@ void initTrainWindow() {
|
||||
|
||||
itemDelegate = new CustomItemDelegate(multiChoiceList);
|
||||
|
||||
{ // Top button menu.
|
||||
auto hTopButtons = new QHBoxLayout();
|
||||
auto topButtons = new QWidget();
|
||||
topButtons->setLayout(hTopButtons);
|
||||
|
||||
auto topLeftSpacer = new QSpacerItem(50, 50, QSizePolicy::Expanding, QSizePolicy::Minimum);
|
||||
auto btnSaveProgress = new QToolButton();
|
||||
btnSaveProgress->setText("Save progress");
|
||||
|
||||
hTopButtons->addItem(topLeftSpacer);
|
||||
hTopButtons->addWidget(btnSaveProgress);
|
||||
vTrainWidget->addWidget(topButtons);
|
||||
|
||||
QObject::connect(btnSaveProgress, &QToolButton::clicked, []() {
|
||||
saveMdem();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
{ // Make the question box.
|
||||
questionBox = new QWidget();
|
||||
vQuestionBox = new QVBoxLayout();
|
||||
@@ -639,16 +739,26 @@ void initTrainWindow() {
|
||||
vButtonBox = new QVBoxLayout();
|
||||
actionButtons = new QWidget();
|
||||
hButtons = new QHBoxLayout();
|
||||
btnPrev = new QToolButton();
|
||||
|
||||
leftSpacer = new QSpacerItem(50, 50, QSizePolicy::Expanding, QSizePolicy::Minimum);
|
||||
|
||||
btnTriggerAnswer = new QToolButton();
|
||||
|
||||
btnNotRemembered = new QToolButton();
|
||||
QObject::connect(btnNotRemembered, &QToolButton::clicked, []() {
|
||||
setCooldownHours(0);
|
||||
});
|
||||
btnHard = new QToolButton();
|
||||
QObject::connect(btnHard, &QToolButton::clicked, []() {
|
||||
setCooldownHours(12);
|
||||
});
|
||||
btnMedium = new QToolButton();
|
||||
QObject::connect(btnMedium, &QToolButton::clicked, []() {
|
||||
setCooldownHours(48);
|
||||
});
|
||||
btnEasy = new QToolButton();
|
||||
|
||||
QObject::connect(btnEasy, &QToolButton::clicked, []() {
|
||||
setCooldownHours(72);
|
||||
});
|
||||
btnNotRemembered->setText("Not remembered");
|
||||
btnHard->setText("Hard");
|
||||
btnMedium->setText("Medium");
|
||||
@@ -659,17 +769,10 @@ void initTrainWindow() {
|
||||
rightSpacer = new QSpacerItem(50, 50, QSizePolicy::Expanding, QSizePolicy::Minimum);
|
||||
btnNext = new QToolButton();
|
||||
|
||||
hButtons->addWidget(btnPrev);
|
||||
hButtons->addItem(leftSpacer);
|
||||
hButtons->addWidget(btnTriggerAnswer);
|
||||
|
||||
hButtons->addWidget(btnNotRemembered);
|
||||
hButtons->addWidget(btnHard);
|
||||
QObject::connect(btnHard, &QToolButton::clicked, []() {
|
||||
const double hourCooldown = 25.0;
|
||||
auto question = trainQuestions[currentQuestionIndex];
|
||||
question->Cooldown = hourCooldown;
|
||||
});
|
||||
hButtons->addWidget(btnMedium);
|
||||
hButtons->addWidget(btnEasy);
|
||||
|
||||
@@ -677,34 +780,13 @@ void initTrainWindow() {
|
||||
hButtons->addWidget(btnNext);
|
||||
vButtonBox->addWidget(actionButtons);
|
||||
actionButtons->setLayout(hButtons);
|
||||
btnPrev->setText("Previous");
|
||||
QObject::connect(btnPrev, &QToolButton::clicked, []() {
|
||||
currentQuestionIndex--;
|
||||
if (currentQuestionIndex > -1) {
|
||||
setupQuestion(trainQuestions[currentQuestionIndex]);
|
||||
}
|
||||
updatePaginationVisibility();
|
||||
});
|
||||
|
||||
btnTriggerAnswer->setText("Show answer");
|
||||
btnTriggerAnswer->hide();
|
||||
|
||||
btnNext->setText("Next");
|
||||
QObject::connect(btnNext, &QToolButton::clicked, []() {
|
||||
switch (practiceAlgoritm) {
|
||||
case PRIMARY:
|
||||
currentQuestionIndex++;
|
||||
if (currentQuestionIndex < trainQuestions.size()) {
|
||||
setupQuestion(trainQuestions[currentQuestionIndex]);
|
||||
}
|
||||
updatePaginationVisibility();
|
||||
break;
|
||||
case RANDOM:
|
||||
// TODO: implement
|
||||
break;
|
||||
case SPACED:
|
||||
// TODO: implement
|
||||
break;
|
||||
}
|
||||
setupNextQuestion();
|
||||
});
|
||||
questionBox->setObjectName("question-box");
|
||||
actionButtons->setStyleSheet(QString(
|
||||
|
||||
@@ -141,6 +141,18 @@ Result<NoneType> ValidateGrammar(const std::vector<Token>& tokens) {
|
||||
return {};
|
||||
}
|
||||
|
||||
time_t parseToUTCTime(const std::string datetime, std::string format) {
|
||||
std::tm tm = {};
|
||||
std::istringstream ss(datetime);
|
||||
ss >> std::get_time(&tm, format.c_str());
|
||||
if (ss.fail()) {
|
||||
throw std::runtime_error("Failed to parse datetime string");
|
||||
}
|
||||
std::time_t time = timegm(&tm);
|
||||
return time;
|
||||
}
|
||||
|
||||
|
||||
Result<ParseInfo> parseQuestions(const std::vector<Token>& tokens) {
|
||||
auto questions = std::vector<Question*>();
|
||||
time_t time = 0;
|
||||
@@ -178,16 +190,14 @@ Result<ParseInfo> parseQuestions(const std::vector<Token>& tokens) {
|
||||
};
|
||||
|
||||
if (isInBounds(i) && tokens[i].tokenType == TokenType::TextFragment) {
|
||||
std::tm tm = {};
|
||||
try {
|
||||
strptime(tokens[i].content.c_str(), "%d.%m.%Y %H:%M", &tm);
|
||||
time = parseToUTCTime(tokens[i].content.c_str(), "%d.%m.%Y %H:%M");
|
||||
} catch (std::exception e) {
|
||||
return makeResult(
|
||||
std::format("cannot parse the time - {}", e.what()),
|
||||
tokens[i]
|
||||
);
|
||||
}
|
||||
time = mktime(&tm);
|
||||
i++;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user