1/* GCompris - Quiz.qml 2* 3* Copyright (C) Siddhesh suthar <siddhesh.it@gmail.com> (Qt Quick port) 4* 5* Authors: 6* Pascal Georges (pascal.georges1@free.fr) (GTK+ version) 7* Holger Kaelberer <holger.k@elberer.de> (Qt Quick port of imageid) 8* Siddhesh suthar <siddhesh.it@gmail.com> (Qt Quick port) 9* Bruno Coudoin <bruno.coudoin@gcompris.net> (Integration Lang dataset) 10* 11* SPDX-License-Identifier: GPL-3.0-or-later 12*/ 13import QtQuick 2.9 14import GCompris 1.0 15import QtGraphicalEffects 1.0 16 17import "../../core" 18import "lang.js" as Activity 19import "quiz.js" as QuizActivity 20 21Item { 22 id: quiz 23 opacity: 0 24 25 property alias background: background 26 property alias bonus: bonus 27 property alias score: score 28 property alias wordImage: wordImage 29 property alias imageFrame: imageFrame 30 property alias wordListModel: wordListModel 31 property alias wordListView: wordListView 32 property alias parser: parser 33 property var goodWord 34 property bool horizontalLayout: background.width >= background.height 35 property bool buttonsBlocked: false 36 37 function init(loadedItems_, wordList_, mode_) { 38 opacity = 1 39 loadedItems_.forceActiveFocus() 40 return QuizActivity.init(loadedItems_, wordList_, mode_) 41 } 42 43 function restoreFocus() { 44 background.forceActiveFocus(); 45 } 46 47 onGoodWordChanged: Activity.playWord(goodWord.voice) 48 49 Behavior on opacity { PropertyAnimation { duration: 200 } } 50 51 Image { 52 id: background 53 source: "qrc:/gcompris/src/activities/lang/resource/imageid-bg.svg" 54 fillMode: Image.PreserveAspectCrop 55 sourceSize.width: width 56 sourceSize.height: height 57 height: parent.height 58 anchors.fill: parent 59 60 property bool keyNavigation: false 61 62 Keys.enabled: !quiz.buttonsBlocked 63 64 Keys.onEscapePressed: { 65 imageReview.start() 66 } 67 Keys.onRightPressed: { 68 keyNavigation = true 69 wordListView.incrementCurrentIndex() 70 } 71 Keys.onLeftPressed: { 72 keyNavigation = true 73 wordListView.decrementCurrentIndex() 74 } 75 Keys.onDownPressed: { 76 keyNavigation = true 77 wordListView.incrementCurrentIndex() 78 } 79 Keys.onUpPressed: { 80 keyNavigation = true 81 wordListView.decrementCurrentIndex() 82 } 83 Keys.onSpacePressed: { 84 keyNavigation = true 85 wordListView.currentItem.children[1].pressed() 86 } 87 Keys.onEnterPressed: { 88 keyNavigation = true 89 wordListView.currentItem.children[1].pressed() 90 } 91 Keys.onReturnPressed: { 92 keyNavigation = true 93 wordListView.currentItem.children[1].pressed() 94 } 95 Keys.onTabPressed: { 96 repeatItem.clicked() 97 } 98 Keys.onReleased: { 99 if (event.key === Qt.Key_Back) { 100 event.accepted = true 101 imageReview.start() 102 } 103 } 104 105 JsonParser { 106 id: parser 107 108 onError: console.error("Lang: Error parsing json: " + msg); 109 } 110 111 ListModel { 112 id: wordListModel 113 } 114 115 Grid { 116 id: gridId 117 columns: quiz.horizontalLayout ? 2 : 1 118 spacing: 0.5 * ApplicationInfo.ratio 119 anchors.fill: parent 120 anchors.margins: 10 * ApplicationInfo.ratio 121 122 Item { 123 width: quiz.horizontalLayout 124 ? background.width * 0.40 125 : background.width - gridId.anchors.margins * 2 126 height: quiz.horizontalLayout 127 ? background.height - bar.height 128 : (background.height - bar.height) * 0.4 129 130 Image { 131 id: imageFrame 132 anchors { 133 horizontalCenter: parent.horizontalCenter 134 verticalCenter: parent.verticalCenter 135 } 136 source: "qrc:/gcompris/src/activities/lang/resource/imageid_frame.svg" 137 sourceSize.width: quiz.horizontalLayout ? parent.width * 0.7 : quiz.width - repeatItem.width - score.width - 50 * ApplicationInfo.ratio 138 z: 11 139 visible: QuizActivity.mode !== 3 140 141 Image { 142 id: wordImage 143 // Images are not svg 144 width: Math.min(parent.width, parent.height) * 0.9 145 height: width 146 anchors.centerIn: parent 147 148 property string nextSource 149 function changeSource(nextSource_) { 150 nextSource = nextSource_ 151 animImage.start() 152 } 153 154 SequentialAnimation { 155 id: animImage 156 PropertyAnimation { 157 target: wordImage 158 property: "opacity" 159 to: 0 160 duration: 100 161 } 162 PropertyAction { 163 target: wordImage 164 property: "source" 165 value: wordImage.nextSource 166 } 167 PropertyAnimation { 168 target: wordImage 169 property: "opacity" 170 to: 1 171 duration: 100 172 } 173 } 174 MouseArea { 175 anchors.fill: parent 176 onClicked: Activity.playWord(goodWord.voice) 177 } 178 } 179 } 180 } 181 182 183 ListView { 184 id: wordListView 185 width: quiz.horizontalLayout 186 ? background.width * 0.55 187 : background.width - gridId.anchors.margins * 2 188 height: quiz.horizontalLayout 189 ? background.height - bar.height 190 : (background.height - bar.height) * 0.60 191 spacing: 2 * ApplicationInfo.ratio 192 orientation: Qt.Vertical 193 verticalLayoutDirection: ListView.TopToBottom 194 interactive: false 195 model: wordListModel 196 197 highlight: Rectangle { 198 width: wordListView.width 199 height: wordListView.buttonHeight 200 color: "lightsteelblue" 201 radius: 5 202 visible: background.keyNavigation 203 y: wordListView.currentItem ? wordListView.currentItem.y : 0 204 Behavior on y { 205 SpringAnimation { 206 spring: 3 207 damping: 0.2 208 } 209 } 210 } 211 highlightFollowsCurrentItem: false 212 focus: true 213 keyNavigationWraps: true 214 215 property int buttonHeight: height / wordListModel.count * 0.9 216 217 delegate: Item { 218 219 id: wordListViewDelegate 220 221 width: wordListView.width 222 height: wordListView.buttonHeight 223 224 Image { 225 id: wordImageQuiz 226 width: height 227 height: wordListView.buttonHeight 228 mipmap: true 229 source: image 230 z: 7 231 fillMode: Image.PreserveAspectFit 232 anchors.leftMargin: 5 * ApplicationInfo.ratio 233 visible: (QuizActivity.mode == 1) ? true : false // hide images after first mini game 234 } 235 236 AnswerButton { 237 id: wordRectangle 238 width: parent.width * 0.6 239 height: wordListView.buttonHeight 240 textLabel: translatedTxt 241 anchors.left: wordImageQuiz.left 242 anchors.right: parent.right 243 blockAllButtonClicks: quiz.buttonsBlocked 244 onPressed: quiz.buttonsBlocked = true 245 isCorrectAnswer: translatedTxt === quiz.goodWord.translatedTxt 246 onIncorrectlyPressed: { 247 // push the error to have it asked again 248 QuizActivity.remainingWords.unshift(quiz.goodWord); 249 QuizActivity.nextSubLevelQuiz(); 250 } 251 onCorrectlyPressed: { 252 QuizActivity.nextSubLevelQuiz(); 253 } 254 } 255 } 256 } 257 } 258 259 BarButton { 260 id: repeatItem 261 source: "qrc:/gcompris/src/core/resource/bar_repeat.svg"; 262 sourceSize.width: 80 * ApplicationInfo.ratio 263 264 z: 12 265 anchors { 266 top: parent.top 267 left: parent.left 268 margins: 10 * ApplicationInfo.ratio 269 } 270 onClicked: Activity.playWord(goodWord.voice) 271 Behavior on opacity { PropertyAnimation { duration: 200 } } 272 } 273 274 Score { 275 id: score 276 parent: quiz 277 } 278 279 Bonus { 280 id: bonus 281 onWin: imageReview.nextMiniGame() 282 } 283 } 284} 285