Developing#1
Conversation
shandomruffle
left a comment
There was a problem hiding this comment.
Я честно, как мог, старался душнить, но по существу стилевых замечаний нашлось мало. Зато есть претензии к работоспособности. Глобально никакой паттерн применён не был (хотя, возможно, я его просто не заметил), что, мне кажется, в паре мест помогло допустить баги. А ещё сорсовых файликов в корневой папке как-то много, их бы раскидать по вложенным, что ли — выглядит слишком угрожающе.
По фичам ощущается некоторый недостаток: QSettings не использован, сложность в переводах не изменяется, звуки молчат, об успешном прохождении ничто не уведомляет.
Итого: код очень красивый, жаль, что не работает 🙃
| void GenerateNextPart() final; | ||
| bool CheckAnswer() final; | ||
|
|
||
| std::vector<std::pair<QString, QString>> exercises_; |
There was a problem hiding this comment.
[nit] вектор из пар — очень по-спшницки, потом путаница с first и second
сюда бы специальную мини-структурку
| static GrammarQuestion GetGrammarFromJson(QJsonObject exercise_obj); | ||
| }; | ||
|
|
||
| #endif // TASKS_LOADER_H_ No newline at end of file |
| layout_->addWidget(task_label_, 1); | ||
|
|
||
| layout_->addWidget(sentence_label_, 2); | ||
|
|
||
| layout_->addWidget(answer_, 3); | ||
|
|
||
| layout_->addWidget(submit_button_, 1); | ||
|
|
||
| layout_->addWidget(progress_bar_, 1); |
There was a problem hiding this comment.
[style] пустые строки для логического разделения блоков кода — это прекрасно, но не после каждой же строчки )
| }; | ||
| }; | ||
|
|
||
| #endif // EMPTY_EXERCISE_H_ No newline at end of file |
| Приложение имеет меню с кнопками выбора типов приложений: ввод перевода или выбор опции. | ||
| Сверху располагается меню с опциями выбора уровня сложности, от которого зависят наборы заданий и | ||
| опциями звука. Меню сложности также может быть вызвано при помощи комбинации `ctrl+c` Также там расположена информация об оставшихся попытках и начисленных очках. | ||
| При привышении заданного максимального количества ошибок выполнение задания прерывается, а при удачном его завершении без ошибок |
There was a problem hiding this comment.
[grammar] превышении )
| We are going for a walk | ||
| My name is Billy | ||
| Mr Herrington is reading a newspaper | ||
| Bill Gates is mining on my PC |
There was a problem hiding this comment.
[minor] такие шикарные файлики, и не используются
There was a problem hiding this comment.
предположу, что json-ы генерились из этих файликов (было бы интересно увидеть скрипт, который это делает)
| variant_2_->setText(exercises_[cur_num_question_ - 1].variants[1]); | ||
| variant_3_->setText(exercises_[cur_num_question_ - 1].variants[2]); | ||
|
|
||
| variant_1_->setChecked(true); |
There was a problem hiding this comment.
[nit] а правильно ли до ответа делать какой-то вариант предвыбранным?
|
|
||
| std::vector<std::pair<QString, QString>> exercises; | ||
|
|
||
| for (const auto &exercise_val : json_exs.value(QString("exercises")).toArray()) { |
There was a problem hiding this comment.
[nit] auto& exercise_val
| exercises.push_back(GetTranslationFromJson(exercise_obj)); | ||
| } | ||
|
|
||
| std::shuffle(exercises.begin(), exercises.end(), std::mt19937(std::random_device()())); |
There was a problem hiding this comment.
[nit] вот тут шафл здорового человека, а в tasks_loader.cpp:82 шафл курильщика, который устарел и был выведен в C++17
|
|
||
| class TasksLoader { | ||
| public: | ||
| static std::vector<std::pair<QString, QString>> LoadTranslation(int cnt, |
There was a problem hiding this comment.
[nit] раз уж QT, то может и структуры использовать из QT, например QVector и QPair? в них и фичи интересные есть, и с qDebug() удобно отлаживаться
There was a problem hiding this comment.
ну тут мы на лекциях обсуждали, что QVector пользоваться не рекомендуется
elizabethfeden
left a comment
There was a problem hiding this comment.
это кусочек ревью, позже добавлю :)
| @@ -0,0 +1,2 @@ | |||
| <?xml version="1.0" encoding="UTF-8"?> | |||
There was a problem hiding this comment.
лишние файлики (ниже тоже)
| connect(exercise_widget_, | ||
| &ExerciseWidget::IncIncorrectSignal, | ||
| this, | ||
| &CentralWidget::IncIncorrect); |
There was a problem hiding this comment.
в целом ChangeToTranslation и ChangeToGrammar почти не отличаются, можно одну функцию сделать с аргументом о том, что именно создавать. Также и два сигнала (ChangeToTranslationSignal и ChangeToGrammarSignal) можно не создавать, а кидать только один с параметром "на что поменять"
| layout_->addWidget(exercise_widget_, 1); | ||
|
|
||
| connect(exercise_widget_, | ||
| &ExerciseWidget::IncScoreSignal, |
There was a problem hiding this comment.
[style] я бы постаралась стилистически сохранить нейминг сигналов qt, т. е. здесь было бы ScoreIncreased, ну и все другие сигналы тоже
| } | ||
|
|
||
| void CentralWidget::IncScore() { | ||
| emit(IncScoreSignal()); |
There was a problem hiding this comment.
[style] обычно после emit не ставят скобочки (как после return)
| layout_->removeWidget(exercise_widget_); | ||
| delete exercise_widget_; | ||
| exercise_widget_ = new GrammarExercise(this, difficulty_level_); |
There was a problem hiding this comment.
непонятно, зачем создавать новый виджет каждый раз, учитывая, что у виджетов можно менять сложность, не пересоздавая их. можно же хранить по экземпляру GrammarExercise и TranslationExercise в полях класса, или даже в QStackedWidget, просто переключая в нем текущий выбор
| void ChoiceWidget::ChangeToTranslation() { | ||
| translation_button_->setStyleSheet("background-color: #8b008b"); | ||
| grammar_button_->setStyleSheet("background-color: #50c878"); | ||
| emit(ChangeToTranslationSignal()); | ||
| } | ||
|
|
||
| void ChoiceWidget::ChangeToGrammar() { | ||
| translation_button_->setStyleSheet("background-color: #50c878"); | ||
| grammar_button_->setStyleSheet("background-color: #8b008b"); | ||
| emit(ChangeToGrammarSignal()); | ||
| } |
There was a problem hiding this comment.
[nit] вот эти две функции тоже можно было заменить одной, принимающей, на что меняем
| emit(ChangeToGrammarSignal()); | ||
| } | ||
|
|
||
| void ChoiceWidget::MyResizeEvent(QResizeEvent* event) { |
There was a problem hiding this comment.
а чем qt-шный resizeevent тут не подошел?
| auto* easy_button(new QRadioButton(tr("Easy"))); | ||
| auto* medium_button(new QRadioButton(tr("Medium"))); | ||
| auto* hard_button(new QRadioButton(tr("Hard"))); | ||
|
|
||
| difficulty_buttons_.append(easy_button); | ||
| difficulty_buttons_.append(medium_button); | ||
| difficulty_buttons_.append(hard_button); |
There was a problem hiding this comment.
| auto* easy_button(new QRadioButton(tr("Easy"))); | |
| auto* medium_button(new QRadioButton(tr("Medium"))); | |
| auto* hard_button(new QRadioButton(tr("Hard"))); | |
| difficulty_buttons_.append(easy_button); | |
| difficulty_buttons_.append(medium_button); | |
| difficulty_buttons_.append(hard_button); | |
| for (const auto& name : {"Easy", "Medium", "Hard"}) { | |
| difficulty_buttons_.append(new QRadioButton(name)) | |
| } |
точно, кстати, им при создании не нужно родителя указывать?
|
|
||
| #include "exercise_widget.h" | ||
|
|
||
| class EmptyExercise : public ExerciseWidget { |
There was a problem hiding this comment.
architecture-wise, для вещей типа "сгенерить новое упражнение" и "проверить ответ" стоило создать класс, не связанный с qt. нужно разделять логку и ее отображение
There was a problem hiding this comment.
зачем вообще, кстати, emptyexercise нужен, непонятно. выглядит, будто и без него можно обойтись
| } | ||
|
|
||
| void ExerciseWidget::RestartFail() { | ||
| auto* wrong_dialog(new QDialog(this)); |
There was a problem hiding this comment.
здесь можно было и стандартным диалогом QMessageBox::information обойтись, там названия кнопок можно менять
elizabethfeden
left a comment
There was a problem hiding this comment.
В целом да, ощущается незаконченность/неотполированность, видно, что не успел добавить фичи и поправить баги.
Архитектура местами кривоватая, хотя с большего норм.
Местами сделано не совсем по тз, предполагалось, например, что главная страница и упражнения не показываются одновременно, а так непонятно, ставить ли баллы за пункты типа "должна быть возможность вернуться к главной странице".
Но все равно молодец конечно, видно, что семестр Qt был не зря, и можешь сделать что-то больше, чем пустое приложение с кнопкой "выход" :)
Антон, ревью отличное, всем довольна.
| We are going for a walk | ||
| My name is Billy | ||
| Mr Herrington is reading a newspaper | ||
| Bill Gates is mining on my PC |
There was a problem hiding this comment.
предположу, что json-ы генерились из этих файликов (было бы интересно увидеть скрипт, который это делает)
| @@ -0,0 +1,14 @@ | |||
| #ifndef GRAMMAR_QUESTION_H_ | |||
There was a problem hiding this comment.
[nit] такие структурки имеет смысл объявлять там же, где они используются, в этом случае в grammar_exercise.h
| void IncScore(); | ||
| void IncIncorrect(); | ||
|
|
||
| void MyResizeEvent(QResizeEvent* event); |
| label_->setText(str); | ||
| } | ||
| void Menu::DecTries() { | ||
| tries_--; |
There was a problem hiding this comment.
в целом проверка на отрицательность не помешала бы
| int score_ = 0; | ||
| int tries_ = 2; | ||
| QLabel* label_; | ||
| MusicClass* music_class_; |
There was a problem hiding this comment.
меня здесь снова архитектурно смущает, что меню почему-то отвечает за музыку. но здесь скорее проблема снова в том, что смешивается несмешиваемое. класс, который отвечает за настройки музыки и класс, который отвечает за проигрывание музыки - разные.
| switch (level) { | ||
| case 0: { | ||
| file_path = ":/exercises/translation_easy.json"; | ||
| break; | ||
| } | ||
| case 1: { | ||
| file_path = ":/exercises/translation_medium.json"; | ||
| break; | ||
| } | ||
| case 2: { | ||
| file_path = ":/exercises/translation_hard.json"; | ||
| break; | ||
| } | ||
| default: { | ||
| break; | ||
| } | ||
| } |
There was a problem hiding this comment.
или на мапку index/enum -> filename
| exercises.resize(cnt); | ||
| exercises.shrink_to_fit(); |
| return exercises; | ||
| } | ||
|
|
||
| std::vector<GrammarQuestion> TasksLoader::LoadGrammar(int cnt, int level) { |
There was a problem hiding this comment.
[style] много дублирования кода с LoadTranslation
| QString question; | ||
| QVector<QString> variants; | ||
| QString answer; | ||
| QString tip; |
There was a problem hiding this comment.
подсказка не используется(
| void TranslationExercise::GenerateNextPart() { | ||
| progress_bar_->setValue(cur_num_question_); | ||
| sentence_label_->setText(exercises_[cur_num_question_++].first); | ||
| answer_->setText(tr("")); |
There was a problem hiding this comment.
зачем тут tr :) вообще, странно эта штука используется, не на всех строках она есть, да и текст сомневаюсь, что планируется переводить
Thanks for checking and have a nice day :)