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

0001 /* GCompris - lang.qml
0002 *
0003 * Copyright (C) Siddhesh suthar <siddhesh.it@gmail.com> (Qt Quick port)
0004 *
0005 * Authors:
0006 *   Pascal Georges (pascal.georges1@free.fr) (GTK+ version)
0007 *   Holger Kaelberer <holger.k@elberer.de> (Qt Quick port of imageid)
0008 *   Siddhesh suthar <siddhesh.it@gmail.com> (Qt Quick port)
0009 *   Bruno Coudoin <bruno.coudoin@gcompris.net> (Integration Lang dataset)
0010 *
0011 *   SPDX-License-Identifier: GPL-3.0-or-later
0012 */
0013 import QtQuick 2.12
0014 import GCompris 1.0
0015 import QtGraphicalEffects 1.0
0016 
0017 import "../../core"
0018 import "lang.js" as Activity
0019 import "qrc:/gcompris/src/core/core.js" as Core
0020 
0021 Item {
0022     id: imageReview
0023     anchors.fill: parent
0024 
0025     property alias category: categoryText.text
0026     property int wordListIndex // This is the current sub list of words
0027     property var word: rootItem.opacity == 1 ? items.wordList[wordListIndex][score.currentSubLevel - 1] : undefined
0028     // miniGames is list of miniGames
0029     // first element is Activity name,
0030     // second element is mode of miniGame
0031     // third element is the qml to load
0032     property var miniGames: [
0033         ["QuizActivity", 1, "Quiz.qml"],
0034         ["QuizActivity", 2, "Quiz.qml"],
0035         ["QuizActivity", 3, "Quiz.qml"],
0036         ["SpellActivity", 1, "SpellIt.qml"]
0037     ]
0038     property var currentMiniGame
0039     property var loadedItems
0040     property bool started: rootItem.opacity == 1
0041 
0042     // Start at last wordListIndex
0043     function start() {
0044         initLevel(wordListIndex)
0045     }
0046 
0047     // Start the image review at wordList sublesson
0048     function initLevel(wordListIndex_) {
0049         wordListIndex = wordListIndex_
0050         score.currentSubLevel = 1
0051         score.numberOfSubLevels = items.wordList[wordListIndex].length
0052         focus = true
0053         forceActiveFocus()
0054         miniGameLoader.source = ""
0055         currentMiniGame = -1
0056         rootItem.opacity = 1
0057     }
0058 
0059     function restoreMinigameFocus() {
0060         miniGameLoader.item.restoreFocus();
0061     }
0062 
0063     function stop() {
0064         focus = false
0065         rootItem.opacity = 0
0066         wordImage.changeSource('')
0067         wordText.changeText('')
0068         repeatItem.visible = false
0069     }
0070 
0071     onWordChanged: {
0072         if(word) {
0073             if (Activity.playWord(word.voice)) {
0074                 word['hasVoice'] = true
0075                 repeatItem.visible = true
0076             } else {
0077                 word['hasVoice'] = false
0078                 repeatItem.visible = false
0079             }
0080             wordImage.changeSource(word.image)
0081             wordText.changeText(word.translatedTxt)
0082         }
0083     }
0084 
0085     //    Cheat codes to access mini games directly
0086     // Note: miniGame 2 (quiz on mode 3) can start only if at least the audio of 2 words
0087     // have been played on ImageReview step, else it skips to miniGame 3. So make sure
0088     // to view all the words on first step before loading miniGame 2.
0089     Keys.onPressed: {
0090         if((event.modifiers & Qt.ControlModifier) && (event.key === Qt.Key_1)) {
0091             initLevel(wordListIndex)
0092             event.accepted = true
0093         }
0094         if((event.modifiers & Qt.ControlModifier) && (event.key === Qt.Key_2)) {
0095             startMiniGame(0)
0096             event.accepted = true
0097         }
0098         if((event.modifiers & Qt.ControlModifier) && (event.key === Qt.Key_3)) {
0099             startMiniGame(1)
0100             event.accepted = true
0101         }
0102         if((event.modifiers & Qt.ControlModifier) && (event.key === Qt.Key_4)) {
0103             startMiniGame(2)
0104             event.accepted = true
0105         }
0106         if((event.modifiers & Qt.ControlModifier) && (event.key === Qt.Key_5)) {
0107             startMiniGame(3)
0108             event.accepted = true
0109         }
0110     }
0111 
0112     Keys.onEscapePressed: {
0113         Activity.launchMenuScreen()
0114     }
0115 
0116     Keys.onLeftPressed: {
0117         if( score.currentSubLevel > 1 ) {
0118             imageReview.prevWord()
0119             event.accepted = true
0120         }
0121     }
0122     Keys.onRightPressed: {
0123         imageReview.nextWord()
0124         event.accepted = true
0125     }
0126     Keys.onSpacePressed: {
0127         imageReview.nextWord()
0128         event.accepted = true
0129     }
0130     Keys.onEnterPressed: {
0131         imageReview.nextWord()
0132         event.accepted = true
0133     }
0134     Keys.onReturnPressed: {
0135         imageReview.nextWord()
0136         event.accepted = true
0137     }
0138     Keys.onTabPressed: {
0139         repeatItem.clicked()
0140     }
0141 
0142     Keys.onReleased: {
0143         if (event.key === Qt.Key_Back) {
0144             event.accepted = true
0145             Activity.launchMenuScreen()
0146         }
0147     }
0148 
0149     Item {
0150         id: rootItem
0151         anchors.fill: parent
0152         opacity: 0
0153         Behavior on opacity { PropertyAnimation { duration: 200 } }
0154 
0155         Rectangle {
0156             id: categoryTextbg
0157             parent: rootItem
0158             width: Math.min(imageFrame.width + 8, imageBg.width * 1.5)
0159             height: 42 * ApplicationInfo.ratio
0160             color: "#AAFFFFFF"
0161             radius: 16
0162             anchors {
0163                 horizontalCenter: parent.horizontalCenter
0164                 top: rootItem.top
0165                 topMargin: 4 * ApplicationInfo.ratio
0166             }
0167 
0168             GCText {
0169                 id: categoryText
0170                 fontSizeMode: Text.Fit
0171                 fontSize: mediumSize
0172                 font.weight: Font.DemiBold
0173                 width: parent.width - 8
0174                 height: parent.height - 8
0175                 horizontalAlignment: Text.AlignHCenter
0176                 verticalAlignment: Text.AlignVCenter
0177                 color: "#373737"
0178                 anchors.centerIn: parent
0179             }
0180         }
0181 
0182         Item {
0183             id: imageFrame
0184             parent: rootItem
0185             width: (parent.width - previousWordButton.width * 2) * 0.8
0186             height: (parent.height - categoryTextbg.height - wordTextbg.height - bar.height * 1.1) * 0.8
0187             anchors {
0188                 horizontalCenter: parent.horizontalCenter
0189                 top: categoryTextbg.bottom
0190                 margins: 10 * ApplicationInfo.ratio
0191             }
0192             z: 11
0193 
0194             Rectangle {
0195                 id: imageBg
0196                 color: "#E0E0F7"
0197                 anchors.centerIn: parent
0198                 width: Math.min(parent.width, parent.height)
0199                 height: width
0200                 radius: width * 0.1
0201                 border.color: "#373737"
0202                 border.width: ApplicationInfo.ratio
0203             }
0204 
0205             Image {
0206                 id: wordImage
0207                 // Images are not svg
0208                 width: imageBg.height * 0.9
0209                 height: width
0210                 anchors.centerIn: parent
0211 
0212                 property string nextSource
0213                 function changeSource(nextSource_) {
0214                     nextSource = nextSource_
0215                     animImage.restart()
0216                 }
0217 
0218                 SequentialAnimation {
0219                     id: animImage
0220                     PropertyAnimation {
0221                         target: wordImage
0222                         property: "opacity"
0223                         to: 0
0224                         duration: 100
0225                     }
0226                     PropertyAction {
0227                         target: wordImage
0228                         property: "source"
0229                         value: wordImage.nextSource
0230                     }
0231                     PropertyAnimation {
0232                         target: wordImage
0233                         property: "opacity"
0234                         to: 1
0235                         duration: 100
0236                     }
0237                 }
0238                 MouseArea {
0239                     anchors.fill: parent
0240                     enabled: rootItem.opacity == 1
0241                     onClicked: Activity.playWord(word.voice)
0242                 }
0243             }
0244         }
0245 
0246         Item {
0247             id: previousButtonArea
0248             anchors.left: rootItem.left
0249             anchors.top: imageFrame.top
0250             anchors.bottom: imageFrame.bottom
0251             width: (rootItem.width - imageBg.width) * 0.5
0252 
0253             Image {
0254                 id: previousWordButton
0255                 source: "qrc:/gcompris/src/core/resource/bar_previous.svg";
0256                 width: 36 * ApplicationInfo.ratio
0257                 sourceSize.width: width
0258                 visible: score.currentSubLevel > 1 ? true : false
0259                 anchors.centerIn: parent
0260 
0261                 MouseArea {
0262                     anchors.centerIn: parent
0263                     enabled: rootItem.opacity == 1
0264                     width: parent.width * 3
0265                     height: parent.height * 2
0266                     onClicked: imageReview.prevWord()
0267                 }
0268             }
0269         }
0270 
0271         Item {
0272             id: nextButtonArea
0273             anchors.right: rootItem.right
0274             anchors.top: imageFrame.top
0275             anchors.bottom: imageFrame.bottom
0276             width: previousButtonArea.width
0277 
0278             Image {
0279                 id: nextWordButton
0280                 source: "qrc:/gcompris/src/core/resource/bar_next.svg";
0281                 width: previousWordButton.width
0282                 sourceSize.width: width
0283                 anchors.centerIn: parent
0284 
0285                 MouseArea {
0286                     anchors.centerIn: parent
0287                     enabled: rootItem.opacity == 1
0288                     width: parent.width * 3
0289                     height: parent.height * 2
0290                     onClicked: imageReview.nextWord();
0291                 }
0292             }
0293         }
0294 
0295         Rectangle {
0296             id: wordTextbg
0297             parent: rootItem
0298             width: Math.min(imageFrame.width + 8, imageBg.width * 2)
0299             height: 64 * ApplicationInfo.ratio
0300             color: "#AAFFFFFF"
0301             radius: 16
0302             anchors {
0303                 horizontalCenter: parent.horizontalCenter
0304                 top: imageFrame.bottom
0305                 margins: 10 * ApplicationInfo.ratio
0306             }
0307 
0308             GCText {
0309                 id: wordText
0310                 text: ""
0311                 fontSizeMode: Text.Fit
0312                 fontSize: largeSize
0313                 font.weight: Font.DemiBold
0314                 width: parent.width - 8
0315                 height: parent.height - 8
0316                 horizontalAlignment: Text.AlignHCenter
0317                 verticalAlignment: Text.AlignVCenter
0318                 anchors.centerIn: parent
0319                 color: "#373737"
0320 
0321                 property string nextWord
0322                 function changeText(nextWord_) {
0323                     nextWord = nextWord_
0324                     animWord.restart()
0325                 }
0326 
0327                 SequentialAnimation {
0328                     id: animWord
0329                     PropertyAnimation {
0330                         target: wordText
0331                         property: "opacity"
0332                         to: 0
0333                         duration: 100
0334                     }
0335                     PropertyAction {
0336                         target: wordText
0337                         property: "text"
0338                         value: wordText.nextWord
0339                     }
0340                     PropertyAnimation {
0341                         target: wordText
0342                         property: "opacity"
0343                         to: 1
0344                         duration: 100
0345                     }
0346                 }
0347             }
0348         }
0349 
0350         BarButton {
0351             id: repeatItem
0352             parent: rootItem
0353             source: "qrc:/gcompris/src/core/resource/bar_repeat.svg";
0354             sourceSize.width: Math.min(categoryTextbg.x, 84 * ApplicationInfo.ratio) - 2 * anchors.margins
0355 
0356             z: 12
0357             anchors {
0358                 top: parent.top
0359                 left: parent.left
0360                 margins: 10 * ApplicationInfo.ratio
0361             }
0362             onClicked: Activity.playWord(imageReview.word.voice)
0363             Behavior on opacity { PropertyAnimation { duration: 200 } }
0364         }
0365 
0366         Score {
0367             id: score
0368             parent: rootItem
0369             isScoreCounter: false
0370         }
0371     }
0372     Loader {
0373         id: miniGameLoader
0374         width: parent.width
0375         height: parent.height
0376         anchors.fill: parent
0377         asynchronous: false
0378     }
0379 
0380     function nextPressed() {
0381         if(currentMiniGame === 0) {
0382             nextSubLevel()
0383         }
0384     }
0385 
0386     function nextWord() {
0387         ++score.currentSubLevel;
0388 
0389         if(score.currentSubLevel == score.numberOfSubLevels + 1) {
0390             nextMiniGame()
0391         }
0392     }
0393 
0394     function prevWord() {
0395         --score.currentSubLevel
0396     }
0397 
0398     function startMiniGame(miniGameIndex) {
0399         currentMiniGame = miniGameIndex
0400         var mode = miniGames[miniGameIndex][1];
0401         var itemToLoad = miniGames[miniGameIndex][2];
0402 
0403         // Starting a minigame we don't want pending voices to play
0404         Activity.clearVoiceQueue()
0405 
0406         // preparing the wordList
0407         var wordList = Core.shuffle(items.wordList[wordListIndex]).slice()
0408 
0409         miniGameLoader.source = itemToLoad;
0410         var loadedItems = miniGameLoader.item
0411 
0412         rootItem.opacity = 0
0413         focus = false
0414 
0415         // Initiate the loaded item mini game
0416         // Some Mini Games may not start because they miss voices
0417         // In this case we try the next one
0418         if(!loadedItems.init(loadedItems, wordList, mode))
0419             nextMiniGame()
0420     }
0421 
0422     //called by a miniGame when it is won
0423     function nextMiniGame() {
0424         if(currentMiniGame < miniGames.length - 1) {
0425             startMiniGame(++currentMiniGame)
0426         } else {
0427             Activity.markProgress()
0428             if(wordListIndex < items.wordList.length - 1) {
0429                 initLevel(wordListIndex + 1)
0430             } else {
0431                 Activity.launchMenuScreen()
0432                 miniGameLoader.source = ""
0433             }
0434         }
0435     }
0436 }