Skip to content

Commit

Permalink
Feedback checklist page (#196)
Browse files Browse the repository at this point in the history
* Add class feedback form initial view

* Add emoji radio bar for answering questions

* Insert questions into a card widget

* Fix formatting

* Initial version of feedback form.

* Use AnimatedContainer for emoji form field

* Clean unused code

* Replace class icon

* Extract questions from Firestore

* Remove context from provider

* Add question type

* Begin saving questions' answers

* Improve answers' saving process

* Save all questions' answers

* Minor code improvements

* Better generalize questions/answers

* Rename variables

* Show feedback button only in debug mode

* Create custom AutocompletePerson widget

* Initiate creation of separate widgets

* Improve questions instantiation logic

* Remove S.of(context)

* Add input questions' validator

* Add input questions' validator

* Create multiple question types

* Create separate question display widget

* Refactor emojis animation

* Realign message at the beginning

* Center anonymous form notice.

* Improve emoji animation and remove Selectable.

* Modify feedback policy message

* Allow users to submit one time only feedback for a class

* Add tests for feedback page

* Align questions to the left

* Remove unused onChanged methods

* Remove unused code

* Add initial checklist concept

* Remove rating questions validator

* Remove card widget from free text answers

* Replace text form field with slider

* Modify feedback page tests

* Create feedback checklist page

* Improve slider responses range

* Make teacher field editable

* Fix failing tests

* Implement remote config functionality

* Fix failing tests

* Fix formatting

* Modify checkboxes active color

* Rename checklist categories

* Make checkboxes clickable

* Listen for changes when submitting feedback

* WIP

* Change question type from input to slider

* Make dropdown answers localizable

* Modify SizedBox height

* Improve home page feedback card

* Fix failing integration tests

* Display checklist page button when feedback is enabled

* Fix failing settings tests

* Fix failing authentication tests

* Fix linter errors

* Add feedback icon tooltip

* Change homepage card interface

* Rename feedback answer class

* Rename feedback provider method

* Make remote config option accessible globally

* Move remote config calls to setUpAndChooseStartScreen method

* Make separate methods for each question type

* Change the order of parameters

* Remove business logic from UI component

* Revert selectable changes

* Replace dynamic type with Map<String, String>

* Fix linter errors

* Fix failing tests

* Rename feedback sections

* Rename feedback checklist class

* Remove old remote config settings

* Remove didChangeDependencies() method

* Inline list build method

* Rename homepage feedback nudge

* Rename variables

* Replace dynamic with bool type

* Replace InfoCard with ActionChip widget

* Use null-checkers

* Check if question index exists in database

* Revise fetchCategories() method comment

* Make provider methods private

* Move remote_config.dart to resources/

* Disable feedback form button if data is still fetching

* Remove getRemoteConfig() method from utils.dart

* Redesign RemoteConfigService class

* Fix feedback nudge visibility

* Fix failing tests

* Remove RemoteConfig constructor and instance variable.

* Allow slider fields with no answer.

* Remove validation from dropdown.

* Fix failing tests

* Remove possibility to add empty answers in database

* Sort feedback categories alphabetically

* Bump version

* Fix exception when slider's TextFormField value is incorrect

* Bump version

* Prepare release for v1.2.12

* Resolve null situations

* Resolve merge conflicts

* Rename methods

* Revert timetable_page.dart

* Change feedback checklist page icon

* Remove unnecessary initState() method

* Inline "where" method

* Remove unnecessary Column widget

* Rename fetchCompletedFeedback() method

* Rename onTap() method

* Remove unnecessary "then" call in async function

* Rename feedback section

* Change "review" to "feedback"

* Rename class_feedback_checklist.dart

* Make feedback nudge text white

* Add TODO item for text wrapping property

Co-authored-by: Ioana Alexandru <[email protected]>
  • Loading branch information
andreicmirciu and IoanaAlexandru authored Jun 20, 2021
1 parent a07eedd commit ffe0290
Show file tree
Hide file tree
Showing 18 changed files with 520 additions and 22 deletions.
4 changes: 4 additions & 0 deletions android/fastlane/metadata/android/en-GB/changelogs/10016.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Added
- You can now submit feedback for all of your classes by pressing the icon in the top right corner of a class page. This option is only available for a limited time, so don't miss the opportunity!
- You can now view a list with all your classes where you completed the feedback form or not.
- You are now notified on the Homepage about how many feedback forms are still waiting to be completed.
4 changes: 4 additions & 0 deletions android/fastlane/metadata/android/en-US/changelogs/10016.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Added
- You can now submit feedback for all of your classes by pressing the icon in the top right corner of a class page. This option is only available for a limited time, so don't miss the opportunity!
- You can now view a list with all your classes where you completed the feedback form or not.
- You are now notified on the Homepage about how many feedback forms are still waiting to be completed.
4 changes: 4 additions & 0 deletions android/fastlane/metadata/android/ro/changelogs/10016.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Adăugat
- Acum poți oferi feedback pentru toate materiile tale, apăsând pe iconița din colțul din dreapta sus de pe pagina unei materii. Această opțiune este disponibilă pentru un timp limitat, așa că nu rata ocazia!
- Acum poți vedea o listă cu toate materiile la care ai completat sau nu formularul de feedback.
- Acum ești notificat pe pagina Acasă referitor la câte formulare de feedback mai așteaptă să fie completate.
24 changes: 15 additions & 9 deletions lib/generated/intl/messages_en.dart
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,15 @@ class MessageLookup extends MessageLookupByLibrary {

static m8(shortcutName) => "Are you sure you want to delete \"${shortcutName}\"?";

static m9(name) => "Welcome, ${name}!";
static m9(number) => "You need to complete ${number} more feedback forms!";

static m10(email) => "There is already an account associated with ${email}.";
static m10(name) => "Welcome, ${name}!";

static m11(n) => "Only ${n} options can be selected at a time.";
static m11(email) => "There is already an account associated with ${email}.";

static m12(provider) => "Please log in with ${provider} to continue.";
static m12(n) => "Only ${n} options can be selected at a time.";

static m13(provider) => "Please log in with ${provider} to continue.";

final messages = _notInlinedMessages(_notInlinedMessages);
static _notInlinedMessages(_) => <String, Function> {
Expand Down Expand Up @@ -204,6 +206,7 @@ class MessageLookup extends MessageLookupByLibrary {
"messageEventDeleted" : MessageLookupByLibrary.simpleMessage("Event deleted successfully."),
"messageEventEdited" : MessageLookupByLibrary.simpleMessage("Event modified successfully."),
"messageFeedbackHasBeenSent" : MessageLookupByLibrary.simpleMessage("The review has been sent successfully."),
"messageFeedbackLeft" : m9,
"messageGetStartedByPressing" : MessageLookupByLibrary.simpleMessage("Get started by pressing the"),
"messageIAgreeToThe" : MessageLookupByLibrary.simpleMessage("I agree to the "),
"messageNewUser" : MessageLookupByLibrary.simpleMessage("New user?"),
Expand All @@ -222,13 +225,14 @@ class MessageLookup extends MessageLookupByLibrary {
"messageWebsiteDeleted" : MessageLookupByLibrary.simpleMessage("Website deleted successfully."),
"messageWebsiteEdited" : MessageLookupByLibrary.simpleMessage("Website modified successfully."),
"messageWebsitePreview" : MessageLookupByLibrary.simpleMessage("Try tapping/long-pressing/hovering the preview to test the new website."),
"messageWelcomeName" : m9,
"messageWelcomeName" : m10,
"messageWelcomeSimple" : MessageLookupByLibrary.simpleMessage("Welcome!"),
"messageYouCanContribute" : MessageLookupByLibrary.simpleMessage("You can contribute to the app data, but you first need to request permissions."),
"navigationAskPermissions" : MessageLookupByLibrary.simpleMessage("Ask for permissions"),
"navigationClassFeedback" : MessageLookupByLibrary.simpleMessage("Review"),
"navigationClassFeedback" : MessageLookupByLibrary.simpleMessage("Feedback"),
"navigationClassInfo" : MessageLookupByLibrary.simpleMessage("Class information"),
"navigationClasses" : MessageLookupByLibrary.simpleMessage("Classes"),
"navigationClassesFeedbackChecklist" : MessageLookupByLibrary.simpleMessage("Feedback checklist"),
"navigationEventDetails" : MessageLookupByLibrary.simpleMessage("Event details"),
"navigationFilter" : MessageLookupByLibrary.simpleMessage("Filter"),
"navigationHome" : MessageLookupByLibrary.simpleMessage("Home"),
Expand All @@ -244,6 +248,8 @@ class MessageLookup extends MessageLookupByLibrary {
"sectionEvents" : MessageLookupByLibrary.simpleMessage("Events"),
"sectionEventsComingUp" : MessageLookupByLibrary.simpleMessage("Events coming up"),
"sectionFAQ" : MessageLookupByLibrary.simpleMessage("FAQ"),
"sectionFeedbackCompleted" : MessageLookupByLibrary.simpleMessage("Feedback completed"),
"sectionFeedbackNeeded" : MessageLookupByLibrary.simpleMessage("Feedback needed"),
"sectionFrequentlyAccessedWebsites" : MessageLookupByLibrary.simpleMessage("Favourite websites"),
"sectionGrading" : MessageLookupByLibrary.simpleMessage("Grading"),
"sectionShortcuts" : MessageLookupByLibrary.simpleMessage("Shortcuts"),
Expand Down Expand Up @@ -287,7 +293,7 @@ class MessageLookup extends MessageLookupByLibrary {
"uniEventTypeTest" : MessageLookupByLibrary.simpleMessage("Test"),
"warningAgreeTo" : MessageLookupByLibrary.simpleMessage("You need to agree to the "),
"warningAuthenticationNeeded" : MessageLookupByLibrary.simpleMessage("Please authenticate in order to access this feature."),
"warningEmailInUse" : m10,
"warningEmailInUse" : m11,
"warningEventNotEditable" : MessageLookupByLibrary.simpleMessage("This event cannot be edited."),
"warningFavouriteWebsitesInitializationFailed" : MessageLookupByLibrary.simpleMessage("Could not read favourite websites."),
"warningFeedbackAlreadySent" : MessageLookupByLibrary.simpleMessage("You have already submitted feedback for this class!"),
Expand All @@ -304,7 +310,7 @@ class MessageLookup extends MessageLookupByLibrary {
"warningNoPrivateWebsite" : MessageLookupByLibrary.simpleMessage("You have not created any private websites yet."),
"warningNoneYet" : MessageLookupByLibrary.simpleMessage("None yet"),
"warningNothingToEdit" : MessageLookupByLibrary.simpleMessage("There is nothing you have permission to edit."),
"warningOnlyNOptionsAtATime" : m11,
"warningOnlyNOptionsAtATime" : m12,
"warningPasswordLength" : MessageLookupByLibrary.simpleMessage("The password must be 8 characters long or more."),
"warningPasswordLowercase" : MessageLookupByLibrary.simpleMessage("The password must include at least one lowercase letter."),
"warningPasswordNumber" : MessageLookupByLibrary.simpleMessage("The password must include at least one number."),
Expand All @@ -315,7 +321,7 @@ class MessageLookup extends MessageLookupByLibrary {
"warningSamePassword" : MessageLookupByLibrary.simpleMessage("The password must be different from the old one."),
"warningTryAgainLater" : MessageLookupByLibrary.simpleMessage("Please try again later."),
"warningUnableToReachNewsFeed" : MessageLookupByLibrary.simpleMessage("Unable to reach the news feed."),
"warningUseProvider" : m12,
"warningUseProvider" : m13,
"warningWebsiteNameExists" : MessageLookupByLibrary.simpleMessage("A website with the same name already exists."),
"warningYouNeedToSelectAssistant" : MessageLookupByLibrary.simpleMessage("You need to select your assistant for this class."),
"warningYouNeedToSelectAtLeastOne" : MessageLookupByLibrary.simpleMessage("You need to select at least one option."),
Expand Down
22 changes: 14 additions & 8 deletions lib/generated/intl/messages_ro.dart
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,15 @@ class MessageLookup extends MessageLookupByLibrary {

static m8(shortcutName) => "Sunteți sigur că doriți să ștergeți \"${shortcutName}\"?";

static m9(name) => "Bine ai venit, ${name}!";
static m9(number) => "Trebuie să completezi încă ${number} formulare de feedback!";

static m10(email) => "Există deja un cont asociat cu adresa ${email}.";
static m10(name) => "Bine ai venit, ${name}!";

static m11(n) => "Doar ${n} opțiuni pot fi selectate la un moment dat.";
static m11(email) => "Există deja un cont asociat cu adresa ${email}.";

static m12(provider) => "Folosiți ${provider} pentru a vă conecta.";
static m12(n) => "Doar ${n} opțiuni pot fi selectate la un moment dat.";

static m13(provider) => "Folosiți ${provider} pentru a vă conecta.";

final messages = _notInlinedMessages(_notInlinedMessages);
static _notInlinedMessages(_) => <String, Function> {
Expand Down Expand Up @@ -204,6 +206,7 @@ class MessageLookup extends MessageLookupByLibrary {
"messageEventDeleted" : MessageLookupByLibrary.simpleMessage("Eveniment șters cu succes."),
"messageEventEdited" : MessageLookupByLibrary.simpleMessage("Eveniment modificat cu succes."),
"messageFeedbackHasBeenSent" : MessageLookupByLibrary.simpleMessage("Feedback trimis cu succes."),
"messageFeedbackLeft" : m9,
"messageGetStartedByPressing" : MessageLookupByLibrary.simpleMessage("Începeți prin a apăsa butonul"),
"messageIAgreeToThe" : MessageLookupByLibrary.simpleMessage("Sunt de acord cu "),
"messageNewUser" : MessageLookupByLibrary.simpleMessage("Utilizator nou?"),
Expand All @@ -222,13 +225,14 @@ class MessageLookup extends MessageLookupByLibrary {
"messageWebsiteDeleted" : MessageLookupByLibrary.simpleMessage("Website-ul a fost șters cu succes."),
"messageWebsiteEdited" : MessageLookupByLibrary.simpleMessage("Website modificat cu succes."),
"messageWebsitePreview" : MessageLookupByLibrary.simpleMessage("Încercați să apăsați, să faceți hover sau să țineți apăsat ca să testați noul website."),
"messageWelcomeName" : m9,
"messageWelcomeName" : m10,
"messageWelcomeSimple" : MessageLookupByLibrary.simpleMessage("Bine ai venit!"),
"messageYouCanContribute" : MessageLookupByLibrary.simpleMessage("Poți contribui la datele din aplicație, dar trebuie mai întâi să ceri permisiuni."),
"navigationAskPermissions" : MessageLookupByLibrary.simpleMessage("Cere permisiuni"),
"navigationClassFeedback" : MessageLookupByLibrary.simpleMessage("Feedback"),
"navigationClassInfo" : MessageLookupByLibrary.simpleMessage("Informații materie"),
"navigationClasses" : MessageLookupByLibrary.simpleMessage("Materii"),
"navigationClassesFeedbackChecklist" : MessageLookupByLibrary.simpleMessage("Listă feedback"),
"navigationEventDetails" : MessageLookupByLibrary.simpleMessage("Detalii eveniment"),
"navigationFilter" : MessageLookupByLibrary.simpleMessage("Filtru"),
"navigationHome" : MessageLookupByLibrary.simpleMessage("Acasă"),
Expand All @@ -244,6 +248,8 @@ class MessageLookup extends MessageLookupByLibrary {
"sectionEvents" : MessageLookupByLibrary.simpleMessage("Evenimente"),
"sectionEventsComingUp" : MessageLookupByLibrary.simpleMessage("Evenimente următoare"),
"sectionFAQ" : MessageLookupByLibrary.simpleMessage("Întrebări frecvente"),
"sectionFeedbackCompleted" : MessageLookupByLibrary.simpleMessage("Feedback completat"),
"sectionFeedbackNeeded" : MessageLookupByLibrary.simpleMessage("Feedback necesar"),
"sectionFrequentlyAccessedWebsites" : MessageLookupByLibrary.simpleMessage("Website-uri favorite"),
"sectionGrading" : MessageLookupByLibrary.simpleMessage("Punctaj"),
"sectionShortcuts" : MessageLookupByLibrary.simpleMessage("Scurtături"),
Expand Down Expand Up @@ -287,7 +293,7 @@ class MessageLookup extends MessageLookupByLibrary {
"uniEventTypeTest" : MessageLookupByLibrary.simpleMessage("Test"),
"warningAgreeTo" : MessageLookupByLibrary.simpleMessage("Trebuie să fiți de acord cu "),
"warningAuthenticationNeeded" : MessageLookupByLibrary.simpleMessage("Autentificați-vă pentru a accesa această funcționalitate."),
"warningEmailInUse" : m10,
"warningEmailInUse" : m11,
"warningEventNotEditable" : MessageLookupByLibrary.simpleMessage("Acest eveniment nu poate fi modificat."),
"warningFavouriteWebsitesInitializationFailed" : MessageLookupByLibrary.simpleMessage("Nu se pot citi date despre site-urile favorite."),
"warningFeedbackAlreadySent" : MessageLookupByLibrary.simpleMessage("Ați trimis deja feedback pentru această materie!"),
Expand All @@ -304,7 +310,7 @@ class MessageLookup extends MessageLookupByLibrary {
"warningNoPrivateWebsite" : MessageLookupByLibrary.simpleMessage("Nu ați creat nici un website privat încă."),
"warningNoneYet" : MessageLookupByLibrary.simpleMessage("Nu există încă"),
"warningNothingToEdit" : MessageLookupByLibrary.simpleMessage("Nu există nimic pentru care să aveți permisiuni de editare."),
"warningOnlyNOptionsAtATime" : m11,
"warningOnlyNOptionsAtATime" : m12,
"warningPasswordLength" : MessageLookupByLibrary.simpleMessage("Parola trebuie să aibă cel puțin 8 caractere."),
"warningPasswordLowercase" : MessageLookupByLibrary.simpleMessage("Parola trebuie să conțină cel putin o minusculă."),
"warningPasswordNumber" : MessageLookupByLibrary.simpleMessage("Parola trebuie să conțină cel puțin un număr."),
Expand All @@ -315,7 +321,7 @@ class MessageLookup extends MessageLookupByLibrary {
"warningSamePassword" : MessageLookupByLibrary.simpleMessage("Parola trebuie sa fie diferită de cea veche."),
"warningTryAgainLater" : MessageLookupByLibrary.simpleMessage("Încercați mai târziu."),
"warningUnableToReachNewsFeed" : MessageLookupByLibrary.simpleMessage("Nu am putut încărca fluxul de știri."),
"warningUseProvider" : m12,
"warningUseProvider" : m13,
"warningWebsiteNameExists" : MessageLookupByLibrary.simpleMessage("Există deja un site cu același nume."),
"warningYouNeedToSelectAssistant" : MessageLookupByLibrary.simpleMessage("Trebuie să selectați asistentul de la această materie."),
"warningYouNeedToSelectAtLeastOne" : MessageLookupByLibrary.simpleMessage("Trebuie să selectați cel puțin o opțiune."),
Expand Down
44 changes: 42 additions & 2 deletions lib/generated/l10n.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion lib/l10n/intl_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@
"sectionEventsComingUp": "Events coming up",
"sectionFAQ": "FAQ",
"sectionGrading": "Grading",
"sectionFeedbackNeeded": "Feedback needed",
"sectionFeedbackCompleted": "Feedback completed",

"shortcutTypeMain": "Main page",
"shortcutTypeClassbook": "Classbook",
Expand Down Expand Up @@ -176,7 +178,8 @@
"navigationEventDetails": "Event details",
"navigationNewsFeed": "News feed",
"navigationClassInfo": "Class information",
"navigationClassFeedback": "Review",
"navigationClassFeedback": "Feedback",
"navigationClassesFeedbackChecklist": "Feedback checklist",

"filterMenuShowAll": "Show all",
"filterMenuShowMine": "Show only mine",
Expand Down Expand Up @@ -271,6 +274,7 @@
"messageYouCanContribute": "You can contribute to the app data, but you first need to request permissions.",
"messageThereAreNoEventsForSelected": "There are no events for the selected ",
"messagePictureUpdatedSuccess": "Profile picture updated successfully.",
"messageFeedbackLeft": "You need to complete {number} more feedback forms!",

"infoPasswordResetEmailSent": "Please check your inbox for the password reset e-mail.",
"infoRelevance": "Try to choose the most restrictive category.",
Expand Down
4 changes: 4 additions & 0 deletions lib/l10n/intl_ro.arb
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@
"sectionEventsComingUp": "Evenimente următoare",
"sectionFAQ": "Întrebări frecvente",
"sectionGrading": "Punctaj",
"sectionFeedbackNeeded": "Feedback necesar",
"sectionFeedbackCompleted": "Feedback completat",

"shortcutTypeMain": "Pagina principală",
"shortcutTypeClassbook": "Catalog",
Expand Down Expand Up @@ -177,6 +179,7 @@
"navigationNewsFeed": "Știri",
"navigationClassInfo": "Informații materie",
"navigationClassFeedback": "Feedback",
"navigationClassesFeedbackChecklist": "Listă feedback",

"filterMenuShowAll": "Arată tot",
"filterMenuShowMine": "Arată doar pe ale mele",
Expand Down Expand Up @@ -271,6 +274,7 @@
"messageYouCanContribute": "Poți contribui la datele din aplicație, dar trebuie mai întâi să ceri permisiuni.",
"messageThereAreNoEventsForSelected": "Nu există evenimente pentru selecția de ",
"messagePictureUpdatedSuccess": "Poza a fost actualizată cu succes.",
"messageFeedbackLeft": "Trebuie să completezi încă {number} formulare de feedback!",

"infoPasswordResetEmailSent": "Please check your inbox for the password reset e-mail.",
"infoRelevance": "Încercați să selectați cea mai restrictivă categorie.",
Expand Down
41 changes: 41 additions & 0 deletions lib/pages/class_feedback/service/feedback_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/cupertino.dart';
import 'package:acs_upb_mobile/widgets/toast.dart';
import 'package:acs_upb_mobile/generated/l10n.dart';
import 'package:acs_upb_mobile/pages/classes/model/class.dart';

extension ClassFeedbackAnswerExtension on FeedbackAnswer {
Map<String, dynamic> toData() {
Expand Down Expand Up @@ -174,6 +175,7 @@ class FeedbackProvider with ChangeNotifier {
true && userSubmittedFeedbackSuccessfully ??
true) ||
(responseAddedSuccessfully && userSubmittedFeedbackSuccessfully)) {
notifyListeners();
return true;
}
return false;
Expand All @@ -198,4 +200,43 @@ class FeedbackProvider with ChangeNotifier {
return false;
}
}

Future<Map<String, bool>> getClassesWithCompletedFeedback(String uid) async {
try {
final DocumentSnapshot snap =
await FirebaseFirestore.instance.collection('users').doc(uid).get();
if (snap.data()['classesFeedback'] != null) {
return Map<String, bool>.from(snap.data()['classesFeedback']);
}
return null;
} catch (e) {
AppToast.show(S.current.errorSomethingWentWrong);
return null;
}
}

Future<String> countClassesWithoutFeedback(
String uid, Set<ClassHeader> userClasses) async {
try {
final Map<String, bool> classesFeedbackCompleted =
await getClassesWithCompletedFeedback(uid);
String feedbackFormsLeft;

if (userClasses != null && classesFeedbackCompleted != null) {
feedbackFormsLeft = userClasses
.where(
(element) => !classesFeedbackCompleted.containsKey(element.id))
.toSet()
.length
.toString();
} else if (userClasses != null && classesFeedbackCompleted == null) {
feedbackFormsLeft = userClasses.length.toString();
}

return feedbackFormsLeft;
} catch (e) {
AppToast.show(S.current.errorSomethingWentWrong);
return null;
}
}
}
Loading

0 comments on commit ffe0290

Please sign in to comment.