Warning, /education/gcompris/src/activities/solar_system/QuizScreen.qml is written in an unsupported language. File is not indexed.

0001 /* GCompris - QuizScreen.qml
0002  *
0003  * SPDX-FileCopyrightText: 2018 Aman Kumar Gupta <gupta2140@gmail.com>
0004  *
0005  * Authors:
0006  *   Aman Kumar Gupta <gupta2140@gmail.com>
0007  *
0008  *   SPDX-License-Identifier: GPL-3.0-or-later
0009  */
0010 import QtQuick 2.12
0011 import GCompris 1.0
0012 import QtGraphicalEffects 1.0
0013 import QtQuick.Controls 2.12
0014 
0015 import "../../core"
0016 import "solar_system.js" as Activity
0017 
0018 Item {
0019     id: mainQuizScreen
0020     width: parent.width
0021     height: parent.height
0022 
0023     property alias score: score
0024     property alias optionListModel: optionListModel
0025     property alias optionListView: optionListView
0026     property alias restartAssessmentMessage: restartAssessmentMessage
0027     property alias blockAnswerButtons: optionListView.blockAnswerButtons
0028     property alias closenessMeter: closenessMeter
0029     property string planetRealImage
0030     property string question
0031     property string closenessMeterValue
0032     property int numberOfCorrectAnswers: 0
0033 
0034     Rectangle {
0035         id: questionArea
0036         anchors.right: score.left
0037         anchors.top: parent.top
0038         anchors.left: parent.left
0039         anchors.margins: 10 * ApplicationInfo.ratio
0040         height: questionText.height + 10 * ApplicationInfo.ratio
0041         color: 'white'
0042         radius: 10
0043         border.width: 3
0044         opacity: 0.8
0045         border.color: "black"
0046         GCText {
0047             id: questionText
0048             horizontalAlignment: Text.AlignHCenter
0049             verticalAlignment: Text.AlignVCenter
0050             anchors.centerIn: parent.Center
0051             color: "black"
0052             width: parent.width
0053             wrapMode: Text.Wrap
0054             text: mainQuizScreen.question
0055         }
0056     }
0057 
0058     // Model of options for a question
0059     ListModel {
0060         id: optionListModel
0061     }
0062 
0063     // This grid has image of the planet in its first column/row (row in case of vertical screen) and the options on the 2nd column/row
0064     Grid {
0065         id: imageAndOptionGrid
0066         columns: (background.horizontalLayout && !items.assessmentMode && items.currentLevel != 1) ? 2 : 1
0067         spacing: 10 * ApplicationInfo.ratio
0068         anchors.top: (questionArea.y + questionArea.height) > (score.y + score.height) ? questionArea.bottom : score.bottom
0069         anchors.left: parent.left
0070         anchors.right: parent.right
0071 
0072         // An item to hold image of the planet
0073         Item {
0074             width: background.horizontalLayout ? background.width * 0.40
0075                                                : background.width - imageAndOptionGrid.anchors.margins * 2
0076             height: background.horizontalLayout ? background.height - bar.height - questionArea.height - 10 * ApplicationInfo.ratio
0077                                                 : (background.height - bar.height - questionArea.height - 10 * ApplicationInfo.ratio) * 0.37
0078 
0079             visible: !items.assessmentMode && (items.currentLevel != 1)
0080 
0081             Image {
0082                 id: planetImageMain
0083                 sourceSize.width: Math.min(parent.width, parent.height) * 0.9
0084                 anchors.centerIn: parent
0085                 source: mainQuizScreen.planetRealImage
0086                 fillMode: Image.PreserveAspectCrop
0087             }
0088         }
0089 
0090         // An item to hold the list view of options
0091         Item {
0092             width: ( items.assessmentMode || items.currentLevel == 1 ) ? mainQuizScreen.width
0093                                                                     : background.horizontalLayout ? background.width * 0.55
0094                                                                                                   : background.width - imageAndOptionGrid.anchors.margins * 2
0095             height: background.horizontalLayout ? itemHeightHorizontal
0096                                                 : itemHeightVertical
0097 
0098             readonly property real itemHeightHorizontal: background.height - bar.height - closenessMeter.height - questionArea.height - 10 * ApplicationInfo.ratio
0099             readonly property real itemHeightVertical: (items.bcurrentLevel != 1 && !items.assessmentMode) ? itemHeightHorizontal * 0.39
0100                                                                                                        : itemHeightHorizontal * 0.8
0101 
0102             ListView {
0103                 id: optionListView
0104                 anchors.verticalCenter: parent.verticalCenter
0105                 anchors.horizontalCenter: parent.horizontalCenter
0106                 width: background.horizontalLayout ? background.width * 0.40
0107                                                    : background.width - imageAndOptionGrid.anchors.margins * 2
0108                 height: background.horizontalLayout ? background.height - bar.height - closenessMeter.height * 1.5 - questionArea.height - 50 * ApplicationInfo.ratio
0109                                                     : parent.itemHeightVertical
0110                 spacing: background.horizontalLayout ? 10 * ApplicationInfo.ratio : 7.5 * ApplicationInfo.ratio
0111                 orientation: Qt.Vertical
0112                 verticalLayoutDirection: ListView.TopToBottom
0113                 interactive: false
0114                 model: optionListModel
0115                 currentIndex: -1
0116 
0117                 readonly property real buttonHeight: (height - 3 * spacing) / 4
0118 
0119                 add: Transition {
0120                     NumberAnimation { properties: "y"; from: parent.y; duration: 500 }
0121                     onRunningChanged: {
0122                         optionListView.blockAnswerButtons = running
0123                     }
0124                 }
0125 
0126                 property bool blockAnswerButtons: false
0127 
0128                 highlight: Rectangle {
0129                     scale: 1.2
0130                     color:  "#2881C3"
0131                     visible: background.keyboardMode
0132                     radius: 10 * ApplicationInfo.ratio
0133                     Behavior on x { SpringAnimation { spring: 2; damping: 0.2 } }
0134                     Behavior on y { SpringAnimation { spring: 2; damping: 0.2 } }
0135                 }
0136 
0137                 delegate: AnswerButton {
0138                     id: optionButton
0139                     width: optionListView.width
0140                     height: optionListView.buttonHeight
0141                     textLabel: optionValue
0142                     blockAllButtonClicks: optionListView.blockAnswerButtons
0143                     audioEffects: activity.audioEffects
0144 
0145                     isCorrectAnswer: closeness === 100
0146 
0147                     onPressed: optionListView.blockAnswerButtons = true
0148                     onIncorrectlyPressed: {
0149                         if(!items.assessmentMode) {
0150                             closenessMeter.stopAnimations()
0151                             closenessMeterIncorrectAnswerAnimation.start()
0152                             mainQuizScreen.closenessMeterValue = closeness
0153                         }
0154                         else {
0155                             optionListView.blockAnswerButtons = false
0156                             Activity.appendAndAddQuestion()
0157                         }
0158                     }
0159                     onCorrectlyPressed: {
0160                         if(!items.assessmentMode) {
0161                             closenessMeter.stopAnimations()
0162                             Activity.currentSubLevel++
0163                             score.currentSubLevel = Activity.currentSubLevel
0164                             score.playWinAnimation()
0165                             particles.burst(30)
0166                             closenessMeterCorrectAnswerAnimation.start()
0167                             mainQuizScreen.closenessMeterValue = closeness
0168                         }
0169                         else {
0170                             Activity.assessmentModeQuestions.shift()
0171                             mainQuizScreen.numberOfCorrectAnswers++
0172                             Activity.nextSubLevel(true)
0173                         }
0174                     }
0175                 }
0176             }
0177         }
0178     }
0179 
0180     Rectangle {
0181         id: closenessMeter
0182         x: ((background.width - items.bar.barZoom * items.bar.fullButton * 5.6) < (width + 10 * ApplicationInfo.ratio) && background.horizontalLayout) ? background.width - width - 42 * ApplicationInfo.ratio : background.width - width - 10 * ApplicationInfo.ratio
0183         y: (background.width - items.bar.barZoom * items.bar.fullButton * 5.6) < (width + 10 * ApplicationInfo.ratio) ? background.height - bar.height - height - 10 * ApplicationInfo.ratio : background.height - height  - 10 * ApplicationInfo.ratio
0184         height: 40 * ApplicationInfo.ratio
0185         width: 150 * ApplicationInfo.ratio
0186         radius: width * 0.06
0187         border.width: 2
0188         border.color: "black"
0189         opacity: 0.78
0190         visible: !items.assessmentMode
0191         Item {
0192             width: parent.width - 3 * ApplicationInfo.ratio
0193             height: parent.height
0194             anchors.centerIn: parent
0195 
0196             GCText {
0197                 id: closenessText
0198                 color: "black"
0199                 anchors.fill: parent
0200                 fontSizeMode: Text.Fit
0201                 horizontalAlignment: Text.AlignHCenter
0202                 verticalAlignment: Text.AlignVCenter
0203                 text: qsTr("Accuracy: %1%").arg(closenessMeterValue)
0204             }
0205         }
0206 
0207         SequentialAnimation {
0208             id: closenessMeterIncorrectAnswerAnimation
0209             onStarted: optionListView.blockAnswerButtons = true
0210             NumberAnimation { target: closenessMeter; property: "scale"; to: 1.1; duration: 450 }
0211             NumberAnimation { target: closenessMeter; property: "scale"; to: 1.0; duration: 450 }
0212             onStopped: optionListView.blockAnswerButtons = false
0213         }
0214 
0215         SequentialAnimation {
0216             id: closenessMeterCorrectAnswerAnimation
0217             onStarted: optionListView.blockAnswerButtons = true
0218             NumberAnimation { target: closenessMeter; property: "scale"; to: 1.1; duration: 450 }
0219             NumberAnimation { target: closenessMeter; property: "scale"; to: 1.0; duration: 450 }
0220             NumberAnimation { target: closenessMeter; property: "scale"; to: 1.1; duration: 450 }
0221             NumberAnimation { target: closenessMeter; property: "scale"; to: 1.0; duration: 450 }
0222             ScriptAction { script: { Activity.nextSubLevel() } }
0223         }
0224 
0225         ParticleSystemStarLoader {
0226             id: particles
0227             clip: false
0228         }
0229 
0230         function stopAnimations() {
0231             optionListView.blockAnswerButtons = false
0232             closenessMeterCorrectAnswerAnimation.stop()
0233             closenessMeterIncorrectAnswerAnimation.stop()
0234         }
0235     }
0236 
0237     GCProgressBar {
0238         id: progressBar
0239         height: bar.height * 0.35
0240         width: parent.width * 0.35
0241 
0242         readonly property real percentage: (mainQuizScreen.numberOfCorrectAnswers / score.numberOfSubLevels) * 100
0243         message: qsTr("%1%").arg(value)
0244 
0245         value: Math.round(percentage * 10) / 10
0246         to: 100
0247 
0248         visible: items.assessmentMode
0249         y: parent.height - bar.height - height - 10 * ApplicationInfo.ratio
0250         x: parent.width - width * 1.1
0251 
0252         Rectangle {
0253             z: -1
0254             radius: 5 * ApplicationInfo.ratio
0255             anchors.centerIn: parent
0256             height: progressBar.height * 1.25
0257             width: parent.width
0258             color: "#80EEEEEE"
0259         }
0260     }
0261 
0262     Rectangle {
0263         id: restartAssessmentMessage
0264         width: parent.width
0265         height: parent.height - bar.height * 1.25
0266         anchors.top: parent.top
0267         anchors.margins: 10 * ApplicationInfo.ratio
0268         anchors.horizontalCenter: parent.horizontalCenter
0269         radius: 4 * ApplicationInfo.ratio
0270         visible: items.assessmentMode && items.restartAssessmentMessage
0271         z: 4
0272         GCText {
0273             anchors.fill: parent
0274             horizontalAlignment: Text.AlignHCenter
0275             verticalAlignment: Text.AlignVCenter
0276             wrapMode: Text.WordWrap
0277             fontSizeMode: mediumSize
0278             text: qsTr("Your final score is: <font color=\"#3bb0de\">%1%</font>.<br><br>%2").arg(progressBar.value).arg(progressBar.value <= 90 ? qsTr("You should score above 90% to become a Solar System expert!<br>Retry to test your skills again or train in normal mode to learn more about the Solar System.") : qsTr("Great! You can replay the assessment to test your knowledge on more questions."))
0279         }
0280 
0281         // To prevent clicking on options under it
0282         MouseArea {
0283             anchors.fill: parent
0284         }
0285 
0286         onVisibleChanged: scaleAnimation.start()
0287 
0288         NumberAnimation {
0289             id: scaleAnimation
0290             target: restartAssessmentMessage
0291             properties: "scale"
0292             from: 0
0293             to: 1
0294             duration: 1500
0295             easing.type: Easing.OutBounce
0296         }
0297     }
0298 
0299     Score {
0300         id: score
0301         anchors.bottom: undefined
0302         anchors.right: parent.right
0303         anchors.rightMargin: 10 * ApplicationInfo.ratio
0304         anchors.top: parent.top
0305         z: 0
0306         isScoreCounter: items.assessmentMode ? false : true
0307     }
0308 }