Commit dee3a9f7 authored by Andreas Cord-Landwehr's avatar Andreas Cord-Landwehr
Browse files

Implement interaction between menu highlight and current phrase

parent 28481d57
......@@ -50,13 +50,13 @@ TrainingAction::TrainingAction(Phrase *phrase, TrainingSession *session, QObject
void TrainingAction::appendChild(QObject* child)
{
m_children.append(child);
emit childrenChanged();
m_actions.append(child);
emit actionsChanged();
}
bool TrainingAction::hasChildren() const
{
return m_children.count() > 0;
return m_actions.count() > 0;
}
void TrainingAction::trigger()
......@@ -80,7 +80,31 @@ void TrainingAction::setEnabled(bool enabled)
emit enabledChanged(m_enabled);
}
bool TrainingAction::checked() const
{
return m_checked;
}
void TrainingAction::setChecked(bool checked)
{
if (checked == m_checked) {
return;
}
m_checked = checked;
emit checkedChanged(m_checked);
}
QObject * TrainingAction::icon() const
{
return m_icon;
}
Phrase * TrainingAction::phrase() const
{
return m_phrase;
}
QList<QObject *> TrainingAction::actions() const
{
return m_actions;
}
......@@ -37,16 +37,11 @@ class ARTIKULATECORE_EXPORT TrainingAction : public QObject
Q_PROPERTY(QObject* icon READ icon CONSTANT)
Q_PROPERTY(bool visible MEMBER m_visible CONSTANT)
Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged)
Q_PROPERTY(bool checked MEMBER m_checked CONSTANT)
Q_PROPERTY(bool checked READ checked NOTIFY checkedChanged)
Q_PROPERTY(QString tooltip MEMBER m_tooltip CONSTANT)
Q_PROPERTY(QList<QObject*> children MEMBER m_children NOTIFY childrenChanged)
Q_PROPERTY(QList<QObject*> children READ actions NOTIFY actionsChanged)
Q_PROPERTY(bool checkable MEMBER m_checkable CONSTANT)
Q_SIGNALS:
void changed();
void childrenChanged();
void enabledChanged(bool enabled);
public:
TrainingAction(QObject *parent = nullptr);
TrainingAction(const QString &text, QObject *parent = nullptr);
......@@ -56,7 +51,17 @@ public:
Q_INVOKABLE void trigger();
bool enabled() const;
void setEnabled(bool enabled);
void setChecked(bool checked);
bool checked() const;
QObject * icon() const;
Phrase * phrase() const;
QList<QObject*> actions() const;
Q_SIGNALS:
void changed();
void actionsChanged();
void enabledChanged(bool enabled);
void checkedChanged(bool checked);
private:
QString m_text;
......@@ -66,7 +71,7 @@ private:
bool m_checked{false};
bool m_checkable{false};
QString m_tooltip{QString()};
QList<QObject*> m_children;
QList<QObject*> m_actions;
Phrase *m_phrase{nullptr};
TrainingSession * m_trainingSession{nullptr};
};
......
......@@ -33,7 +33,6 @@ TrainingSession::TrainingSession(QObject *parent)
, m_profileManager(nullptr)
, m_course(nullptr)
, m_unit(nullptr)
, m_phrase(nullptr)
{
}
......@@ -107,44 +106,55 @@ void TrainingSession::setUnit(Unit *unit)
return unitChanged();
}
Phrase * TrainingSession::phrase() const
TrainingAction * TrainingSession::activeAction() const
{
return m_phrase;
if (m_indexUnit < 0 || m_indexPhrase < 0) {
return nullptr;
}
return qobject_cast<TrainingAction*>(m_actions.at(m_indexUnit)->actions().at(m_indexPhrase));
}
void TrainingSession::setPhrase(Phrase *phrase)
Phrase * TrainingSession::activePhrase() const
{
if (m_phrase == phrase) {
return;
if (const auto action = activeAction()) {
return action->phrase();
}
setUnit(phrase->unit());
m_phrase = phrase;
return phraseChanged();
return nullptr;
}
Phrase * TrainingSession::nextPhrase() const
void TrainingSession::setPhrase(Phrase *phrase)
{
if (!m_phrase) {
return nullptr;
}
const int index = m_phrase->unit()->phraseList().indexOf(m_phrase);
if (index < m_phrase->unit()->phraseList().length() - 1) {
return m_phrase->unit()->phraseList().at(index + 1);
} else {
Unit *unit = m_phrase->unit();
int uIndex = unit->course()->unitList().indexOf(unit);
if (uIndex < unit->course()->unitList().length() - 1) {
return unit->course()->unitList().at(uIndex + 1)->phraseList().first();
for (int i = 0; i < m_actions.count(); ++i) {
for (int j = 0; j < m_actions.at(i)->actions().count(); ++j) {
const auto testPhrase = qobject_cast<TrainingAction*>(m_actions.at(i)->actions().at(j))->phrase();
if (phrase == testPhrase) {
if (auto action = activeAction()) {
action->setChecked(false);
}
m_indexUnit = i;
m_indexPhrase = j;
if (auto action = activeAction()) {
action->setChecked(true);
}
emit phraseChanged();
return;
}
}
}
return nullptr;
}
void TrainingSession::showNextPhrase()
void TrainingSession::accept()
{
Q_ASSERT(m_indexUnit >= 0);
Q_ASSERT(m_indexPhrase >= 0);
if (m_indexUnit < 0 || m_indexPhrase < 0) {
return;
}
auto phrase = activePhrase();
// possibly update goals of learner
updateGoal();
m_phrase->updateProgress(Phrase::Progress::Done);
phrase->updateProgress(Phrase::Progress::Done);
// store training activity
LearnerProfile::LearningGoal * goal = m_profileManager->goal(
......@@ -152,19 +162,26 @@ void TrainingSession::showNextPhrase()
m_profileManager->recordProgress(m_profileManager->activeProfile(),
goal,
m_course->id(),
m_phrase->id(),
phrase->id(),
static_cast<int>(LearnerProfile::ProfileManager::Skip),
m_phrase->progress()
phrase->progress()
);
setPhrase(nextPhrase());
selectNextPhrase();
}
void TrainingSession::skipPhrase()
void TrainingSession::skip()
{
Q_ASSERT(m_indexUnit >= 0);
Q_ASSERT(m_indexPhrase >= 0);
if (m_indexUnit < 0 || m_indexPhrase < 0) {
return;
}
// possibly update goals of learner
updateGoal();
m_phrase->updateProgress(Phrase::Progress::Skip);
auto phrase = activePhrase();
phrase->updateProgress(Phrase::Progress::Skip);
// store training activity
LearnerProfile::LearningGoal * goal = m_profileManager->goal(
......@@ -172,17 +189,39 @@ void TrainingSession::skipPhrase()
m_profileManager->recordProgress(m_profileManager->activeProfile(),
goal,
m_course->id(),
m_phrase->id(),
phrase->id(),
static_cast<int>(LearnerProfile::ProfileManager::Skip),
m_phrase->progress()
phrase->progress()
);
setPhrase(nextPhrase());
selectNextPhrase();
}
void TrainingSession::selectNextPhrase()
{
if (auto action = activeAction()) {
action->setChecked(false);
}
// try to find next phrase, otherwise return completed
if (m_indexPhrase >= m_actions.at(m_indexUnit)->actions().count() - 1) {
if (m_indexUnit >= m_actions.count() - 1) {
emit completed();
} else {
++m_indexUnit;
m_indexPhrase = 0;
}
} else {
++m_indexPhrase;
}
if (auto action = activeAction()) {
action->setChecked(true);
}
emit phraseChanged();
}
bool TrainingSession::hasNextPhrase() const
bool TrainingSession::hasNext() const
{
return nextPhrase() != nullptr;
return m_indexUnit < m_actions.count() - 1 || m_indexPhrase < m_actions.last()->actions().count() - 1;
}
void TrainingSession::updateGoal()
......
......@@ -44,8 +44,8 @@ class ARTIKULATECORE_EXPORT TrainingSession : public QObject
Q_OBJECT
Q_PROPERTY(Course *course READ course WRITE setCourse NOTIFY courseChanged)
Q_PROPERTY(Unit *unit READ unit WRITE setUnit NOTIFY unitChanged)
Q_PROPERTY(Phrase *phrase READ phrase WRITE setPhrase NOTIFY phraseChanged)
Q_PROPERTY(bool hasNextPhrase READ hasNextPhrase NOTIFY phraseChanged)
Q_PROPERTY(Phrase *phrase READ activePhrase WRITE setPhrase NOTIFY phraseChanged)
Q_PROPERTY(bool hasNext READ hasNext NOTIFY phraseChanged)
public:
explicit TrainingSession(QObject *parent = nullptr);
......@@ -55,30 +55,36 @@ public:
void setCourse(Course *course);
Unit * unit() const;
void setUnit(Unit *unit);
Phrase::Type phraseType() const;
void setPhraseType(Phrase::Type type);
Phrase * phrase() const;
TrainingAction * activeAction() const;
Phrase * activePhrase() const;
void setPhrase(Phrase *phrase);
bool hasPreviousPhrase() const;
bool hasNextPhrase() const;
Q_INVOKABLE void showNextPhrase();
Q_INVOKABLE void skipPhrase();
bool hasNext() const;
Q_INVOKABLE void accept();
Q_INVOKABLE void skip();
QVector<TrainingAction *> trainingActions();
Q_SIGNALS:
void courseChanged();
void unitChanged();
void phraseChanged();
/**
* @brief Emitted when last phrase of session is skipped or marked as completed.
*/
void completed();
private:
Q_DISABLE_COPY(TrainingSession)
void selectNextPhrase();
Phrase * nextPhrase() const;
void updateGoal();
LearnerProfile::ProfileManager *m_profileManager;
Course *m_course;
Unit *m_unit;
Phrase *m_phrase;
QVector<TrainingAction*> m_actions;
int m_indexUnit{-1};
int m_indexPhrase{-1};
};
#endif
......@@ -47,14 +47,16 @@ Kirigami2.Page {
actions {
main: Kirigami2.Action {
text: i18n("Next")
tooltip: i18n("Mark current phrase as completed and proceed with next one.")
iconName: "dialog-ok"
onTriggered: g_trainingSession.showNextPhrase()
onTriggered: g_trainingSession.accept()
}
right: Kirigami2.Action {
text: i18n("Skip")
tooltip: i18n("Skip current phrase and proceed with next one.")
iconName: "go-next"
enabled: g_trainingSession.hasNextPhrase
onTriggered: g_trainingSession.skipPhrase()
enabled: g_trainingSession.hasNext
onTriggered: g_trainingSession.skip()
}
}
Rectangle {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment