diff --git a/src/activities/lang/ImageReview.qml b/src/activities/lang/ImageReview.qml index 1e738d205..307c9b106 100644 --- a/src/activities/lang/ImageReview.qml +++ b/src/activities/lang/ImageReview.qml @@ -1,415 +1,414 @@ /* GCompris - lang.qml * * Copyright (C) Siddhesh suthar (Qt Quick port) * * Authors: * Pascal Georges (pascal.georges1@free.fr) (GTK+ version) * Holger Kaelberer (Qt Quick port of imageid) * Siddhesh suthar (Qt Quick port) * Bruno Coudoin (Integration Lang dataset) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ import QtQuick 2.1 import GCompris 1.0 import QtGraphicalEffects 1.0 import "../../core" import "lang.js" as Activity import "qrc:/gcompris/src/core/core.js" as Core Item { id: imageReview anchors.fill: parent property alias category: categoryText.text property int wordListIndex // This is the current sub list of words property var word: rootItem.opacity == 1 ? items.wordList[wordListIndex][score.currentSubLevel - 1] : undefined // miniGames is list of miniGames // first element is Activity name, // second element is mode of miniGame // third element is the qml to load property var miniGames: [ ["QuizActivity", 1, "Quiz.qml"], ["QuizActivity", 2, "Quiz.qml"], ["QuizActivity", 3, "Quiz.qml"], ["SpellActivity", 1, "SpellIt.qml"] ] property var currentMiniGame property var loadedItems property bool started: rootItem.opacity == 1 // Start at last wordListIndex function start() { initLevel(wordListIndex) } // Start the image review at wordList sublesson function initLevel(wordListIndex_) { wordListIndex = wordListIndex_ score.currentSubLevel = 1 score.numberOfSubLevels = items.wordList[wordListIndex].length focus = true forceActiveFocus() miniGameLoader.source = "" currentMiniGame = -1 rootItem.opacity = 1 } function stop() { focus = false rootItem.opacity = 0 wordImage.changeSource('') wordText.changeText('') repeatItem.visible = false } onWordChanged: { if(word) { if (Activity.playWord(word.voice)) { word['hasVoice'] = true repeatItem.visible = true } else { word['hasVoice'] = false repeatItem.visible = false } wordImage.changeSource(word.image) wordText.changeText(word.translatedTxt) } } // Cheat codes to access mini games directly Keys.onPressed: { if((event.modifiers & Qt.ControlModifier) && (event.key === Qt.Key_1)) { initLevel(wordListIndex) event.accepted = true } if((event.modifiers & Qt.ControlModifier) && (event.key === Qt.Key_2)) { startMiniGame(0) event.accepted = true } if((event.modifiers & Qt.ControlModifier) && (event.key === Qt.Key_3)) { startMiniGame(1) event.accepted = true } if((event.modifiers & Qt.ControlModifier) && (event.key === Qt.Key_4)) { startMiniGame(2) event.accepted = true } if((event.modifiers & Qt.ControlModifier) && (event.key === Qt.Key_5)) { startMiniGame(3) event.accepted = true } } Keys.onEscapePressed: { Activity.launchMenuScreen() } Keys.onLeftPressed: { if( score.currentSubLevel > 1 ) { imageReview.prevWord() event.accepted = true } } Keys.onRightPressed: { imageReview.nextWord() event.accepted = true } Keys.onSpacePressed: { imageReview.nextWord() event.accepted = true } Keys.onEnterPressed: { imageReview.nextWord() event.accepted = true } Keys.onReturnPressed: { imageReview.nextWord() event.accepted = true } Item { id: rootItem anchors.fill: parent opacity: 0 Behavior on opacity { PropertyAnimation { duration: 200 } } - - - Rectangle { - id: categoryTextbg - parent: rootItem - x: categoryText.x - 4 - y: categoryText.y - 4 - width: imageFrame.width + 8 - height: categoryText.height + 8 - color: "#5090ff" - border.color: "#000000" - border.width: 2 - radius: 16 - anchors { - horizontalCenter: parent.horizontalCenter - top: rootItem.top - topMargin: 4 * ApplicationInfo.ratio - } - GCText { - id: categoryText - fontSize: mediumSize - font.weight: Font.DemiBold - width: parent.width - 8 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - color: "white" - wrapMode: Text.WordWrap - } - } + Rectangle { + id: categoryTextbg + parent: rootItem + x: categoryText.x - 4 + y: categoryText.y - 4 + width: imageFrame.width + 8 + height: categoryText.height + 8 + color: "#5090ff" + border.color: "#000000" + border.width: 2 + radius: 16 + anchors { + horizontalCenter: parent.horizontalCenter + top: rootItem.top + topMargin: 4 * ApplicationInfo.ratio + } - Image { - id: imageFrame - parent: rootItem - source: "qrc:/gcompris/src/activities/lang/resource/imageid_frame.svg" - sourceSize.width: Math.min((parent.width - previousWordButton.width * 2) * 0.8, - (parent.height - categoryTextbg.height - - wordTextbg.height - bar.height) * 1.1) - anchors { - horizontalCenter: parent.horizontalCenter - top: categoryTextbg.bottom - margins: 10 * ApplicationInfo.ratio + GCText { + id: categoryText + fontSize: mediumSize + font.weight: Font.DemiBold + width: parent.width - 8 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + color: "white" + wrapMode: Text.WordWrap + } } - z: 11 Image { - id: wordImage - // Images are not svg - width: Math.min(parent.width, parent.height) * 0.9 - height: width - anchors.centerIn: parent - - property string nextSource - function changeSource(nextSource_) { - nextSource = nextSource_ - animImage.start() + id: imageFrame + parent: rootItem + source: "qrc:/gcompris/src/activities/lang/resource/imageid_frame.svg" + sourceSize.width: Math.min((parent.width - previousWordButton.width * 2) * 0.8, + (parent.height - categoryTextbg.height + - wordTextbg.height - bar.height) * 1.1) + anchors { + horizontalCenter: parent.horizontalCenter + top: categoryTextbg.bottom + margins: 10 * ApplicationInfo.ratio } - - SequentialAnimation { - id: animImage - PropertyAnimation { - target: wordImage - property: "opacity" - to: 0 - duration: 100 + z: 11 + + Image { + id: wordImage + // Images are not svg + width: Math.min(parent.width, parent.height) * 0.9 + height: width + anchors.centerIn: parent + + property string nextSource + function changeSource(nextSource_) { + nextSource = nextSource_ + animImage.start() } - PropertyAction { - target: wordImage - property: "source" - value: wordImage.nextSource + + SequentialAnimation { + id: animImage + PropertyAnimation { + target: wordImage + property: "opacity" + to: 0 + duration: 100 + } + PropertyAction { + target: wordImage + property: "source" + value: wordImage.nextSource + } + PropertyAnimation { + target: wordImage + property: "opacity" + to: 1 + duration: 100 + } } - PropertyAnimation { - target: wordImage - property: "opacity" - to: 1 - duration: 100 + MouseArea { + anchors.fill: parent + enabled: rootItem.opacity == 1 + onClicked: Activity.playWord(word.voice) } } - MouseArea { - anchors.fill: parent - enabled: rootItem.opacity == 1 - onClicked: Activity.playWord(word.voice) - } - } - Image { - id: previousWordButton - source: "qrc:/gcompris/src/core/resource/bar_previous.svg"; - sourceSize.width: 30 * 1.2 * ApplicationInfo.ratio - visible: score.currentSubLevel > 1 ? true : false - anchors { - right: parent.left - rightMargin: 30 - top: parent.top - topMargin: parent.height/2 - previousWordButton.height/2 - } - MouseArea { - id: previousWordButtonArea - anchors.fill: parent - onClicked: imageReview.prevWord() + Image { + id: previousWordButton + source: "qrc:/gcompris/src/core/resource/bar_previous.svg"; + sourceSize.width: 30 * 1.2 * ApplicationInfo.ratio + visible: score.currentSubLevel > 1 ? true : false + anchors { + right: parent.left + rightMargin: 30 + top: parent.top + topMargin: parent.height/2 - previousWordButton.height/2 + } + MouseArea { + id: previousWordButtonArea + anchors.fill: parent + onClicked: imageReview.prevWord() + } } - } - Image { - id: nextWordButton - source: "qrc:/gcompris/src/core/resource/bar_next.svg"; - sourceSize.width: 30 * 1.2 * ApplicationInfo.ratio - anchors { - left: parent.right - leftMargin: 30 - top: parent.top - topMargin: parent.height/2 - previousWordButton.height/2 - } - MouseArea { - id: nextWordButtonArea - anchors.fill: parent - onClicked: imageReview.nextWord(); + Image { + id: nextWordButton + source: "qrc:/gcompris/src/core/resource/bar_next.svg"; + sourceSize.width: 30 * 1.2 * ApplicationInfo.ratio + anchors { + left: parent.right + leftMargin: 30 + top: parent.top + topMargin: parent.height/2 - previousWordButton.height/2 + } + MouseArea { + id: nextWordButtonArea + anchors.fill: parent + onClicked: imageReview.nextWord(); + } } } - } - - Rectangle { - id: wordTextbg - parent: rootItem - x: wordText.x - 4 - y: wordText.y - 4 - width: imageFrame.width - height: wordText.height + 4 - color: "#5090ff" - border.color: "#000000" - border.width: 2 - radius: 16 - anchors { - top: imageFrame.bottom - left: imageFrame.left - margins: 10 * ApplicationInfo.ratio - } - GCText { - id: wordText - text: "" - fontSize: largeSize - font.weight: Font.DemiBold - width: parent.width - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - color: "white" - wrapMode: Text.WordWrap - - property string nextWord - function changeText(nextWord_) { - nextWord = nextWord_ - animWord.start() + Rectangle { + id: wordTextbg + parent: rootItem + x: wordText.x - 4 + y: wordText.y - 4 + width: imageFrame.width + height: wordText.height + 4 + color: "#5090ff" + border.color: "#000000" + border.width: 2 + radius: 16 + anchors { + top: imageFrame.bottom + left: imageFrame.left + margins: 10 * ApplicationInfo.ratio } - SequentialAnimation { - id: animWord - PropertyAnimation { - target: wordText - property: "opacity" - to: 0 - duration: 100 + GCText { + id: wordText + text: "" + fontSize: largeSize + font.weight: Font.DemiBold + width: parent.width + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + color: "white" + wrapMode: Text.WordWrap + + property string nextWord + function changeText(nextWord_) { + nextWord = nextWord_ + animWord.start() } - PropertyAction { - target: wordText - property: "text" - value: wordText.nextWord - } - PropertyAnimation { - target: wordText - property: "opacity" - to: 1 - duration: 100 + + SequentialAnimation { + id: animWord + PropertyAnimation { + target: wordText + property: "opacity" + to: 0 + duration: 100 + } + PropertyAction { + target: wordText + property: "text" + value: wordText.nextWord + } + PropertyAnimation { + target: wordText + property: "opacity" + to: 1 + duration: 100 + } } } } - } - BarButton { - id: repeatItem - parent: rootItem - source: "qrc:/gcompris/src/core/resource/bar_repeat.svg"; - sourceSize.width: 80 * ApplicationInfo.ratio - - z: 12 - anchors { - top: parent.top - left: parent.left - margins: 10 * ApplicationInfo.ratio + BarButton { + id: repeatItem + parent: rootItem + source: "qrc:/gcompris/src/core/resource/bar_repeat.svg"; + sourceSize.width: 80 * ApplicationInfo.ratio + + z: 12 + anchors { + top: parent.top + left: parent.left + margins: 10 * ApplicationInfo.ratio + } + onClicked: Activity.playWord(imageReview.word.voice) + Behavior on opacity { PropertyAnimation { duration: 200 } } } - onClicked: Activity.playWord(imageReview.word.voice) - Behavior on opacity { PropertyAnimation { duration: 200 } } - } - Score { - id: score - parent: rootItem - anchors.bottom: undefined - anchors.bottomMargin: 10 * ApplicationInfo.ratio - anchors.right: parent.right - anchors.rightMargin: 10 * ApplicationInfo.ratio - anchors.top: parent.top - } + Score { + id: score + parent: rootItem + anchors.bottom: undefined + anchors.bottomMargin: 10 * ApplicationInfo.ratio + anchors.right: parent.right + anchors.rightMargin: 10 * ApplicationInfo.ratio + anchors.top: parent.top + } } Loader { id: miniGameLoader width: parent.width height: parent.height anchors.fill: parent asynchronous: false } function nextPressed() { if(currentMiniGame == 0) { nextSubLevel() } } function nextWord() { ++score.currentSubLevel; if(score.currentSubLevel == score.numberOfSubLevels + 1) { nextMiniGame() } } function prevWord() { --score.currentSubLevel } function startMiniGame(miniGameIndex) { currentMiniGame = miniGameIndex var mode = miniGames[miniGameIndex][1]; var itemToLoad = miniGames[miniGameIndex][2]; // Starting a minigame we don't wan't pending voices to play Activity.clearVoiceQueue() // preparing the wordList var wordList = Core.shuffle(items.wordList[wordListIndex]).slice() miniGameLoader.source = itemToLoad; var loadedItems = miniGameLoader.item rootItem.opacity = 0 focus = false // Initiate the loaded item mini game // Some Mini Games may not start because they miss voices // In this case we try the next one if(!loadedItems.init(loadedItems, wordList, mode)) nextMiniGame() } //called by a miniGame when it is won function nextMiniGame() { if(currentMiniGame < miniGames.length - 1) { startMiniGame(++currentMiniGame) } else { Activity.markProgress() if(wordListIndex < items.wordList.length - 1) { initLevel(wordListIndex + 1) } else { Activity.launchMenuScreen() } } } } diff --git a/src/activities/lang/Quiz.qml b/src/activities/lang/Quiz.qml index 144158068..54f5a004a 100644 --- a/src/activities/lang/Quiz.qml +++ b/src/activities/lang/Quiz.qml @@ -1,285 +1,284 @@ /* GCompris - Quiz.qml * * Copyright (C) Siddhesh suthar (Qt Quick port) * * Authors: * Pascal Georges (pascal.georges1@free.fr) (GTK+ version) * Holger Kaelberer (Qt Quick port of imageid) * Siddhesh suthar (Qt Quick port) * Bruno Coudoin (Integration Lang dataset) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ import QtQuick 2.1 import GCompris 1.0 import QtGraphicalEffects 1.0 import "../../core" import "lang.js" as Activity import "quiz.js" as QuizActivity Item { id: quiz opacity: 0 property alias background: background property alias bonus: bonus property alias score: score property alias wordImage: wordImage property alias imageFrame: imageFrame property alias wordListModel: wordListModel property alias wordListView: wordListView property alias parser: parser property variant goodWord property bool horizontalLayout: background.width > background.height function init(loadedItems_, wordList_, mode_) { opacity = 1 loadedItems_.forceActiveFocus() return QuizActivity.init(loadedItems_, wordList_, mode_) } onGoodWordChanged: Activity.playWord(goodWord.voice) Behavior on opacity { PropertyAnimation { duration: 200 } } Image { id: background source: "qrc:/gcompris/src/activities/lang/resource/imageid-bg.svg" fillMode: Image.PreserveAspectCrop sourceSize.width: Math.max(parent.width, parent.height) height: parent.height anchors.fill: parent property bool keyNavigation: false Keys.onEscapePressed: { imageReview.start() } Keys.onRightPressed: { keyNavigation = true wordListView.incrementCurrentIndex() } Keys.onLeftPressed: { keyNavigation = true wordListView.decrementCurrentIndex() } Keys.onDownPressed: { keyNavigation = true wordListView.incrementCurrentIndex() } Keys.onUpPressed: { keyNavigation = true wordListView.decrementCurrentIndex() } Keys.onSpacePressed: { keyNavigation = true wordListView.currentItem.children[1].pressed() } Keys.onEnterPressed: { keyNavigation = true wordListView.currentItem.children[1].pressed() } Keys.onReturnPressed: { keyNavigation = true wordListView.currentItem.children[1].pressed() } JsonParser { id: parser onError: console.error("Lang: Error parsing json: " + msg); } ListModel { id: wordListModel } Grid { id: gridId columns: quiz.horizontalLayout ? 2 : 1 spacing: 10 * ApplicationInfo.ratio anchors.fill: parent anchors.margins: 10 * ApplicationInfo.ratio Item { width: quiz.horizontalLayout ? background.width * 0.40 : background.width - gridId.anchors.margins * 2 height: quiz.horizontalLayout ? background.height - bar.height : (background.height - bar.height) * 0.4 Image { id: imageFrame anchors { horizontalCenter: parent.horizontalCenter verticalCenter: parent.verticalCenter } source: "qrc:/gcompris/src/activities/lang/resource/imageid_frame.svg" sourceSize.width: quiz.horizontalLayout ? parent.width * 0.7 : quiz.width - repeatItem.width - score.width - 50 * ApplicationInfo.ratio z: 11 visible: QuizActivity.mode !== 3 Image { id: wordImage // Images are not svg width: Math.min(parent.width, parent.height) * 0.9 height: width anchors.centerIn: parent property string nextSource function changeSource(nextSource_) { nextSource = nextSource_ animImage.start() } SequentialAnimation { id: animImage PropertyAnimation { target: wordImage property: "opacity" to: 0 duration: 100 } PropertyAction { target: wordImage property: "source" value: wordImage.nextSource } PropertyAnimation { target: wordImage property: "opacity" to: 1 duration: 100 } } MouseArea { anchors.fill: parent onClicked: Activity.playWord(goodWord.voice) } } } } ListView { id: wordListView width: quiz.horizontalLayout ? background.width * 0.55 : background.width - gridId.anchors.margins * 2 height: quiz.horizontalLayout ? background.height - bar.height : (background.height - bar.height) * 0.60 spacing: 10 * ApplicationInfo.ratio orientation: Qt.Vertical verticalLayoutDirection: ListView.TopToBottom interactive: false model: wordListModel highlight: Rectangle { width: wordListView.width height: wordListView.buttonHeight color: "lightsteelblue" radius: 5 visible: background.keyNavigation y: wordListView.currentItem.y Behavior on y { SpringAnimation { spring: 3 damping: 0.2 } } } highlightFollowsCurrentItem: false focus: true keyNavigationWraps: true property int buttonHeight: height / wordListModel.count * 0.9 delegate: Item { id: wordListViewDelegate width: wordListView.width height: wordListView.buttonHeight anchors.right: parent.right anchors.left: parent.left Image { id: wordImageQuiz width: height height: wordListView.buttonHeight source: image z: 7 fillMode: Image.PreserveAspectFit anchors.leftMargin: 5 * ApplicationInfo.ratio visible: (QuizActivity.mode == 1) ? true : false // hide images after first mini game } AnswerButton { id: wordRectangle width: parent.width * 0.6 height: wordListView.buttonHeight textLabel: translatedTxt anchors.left: wordImageQuiz.left anchors.right: parent.right isCorrectAnswer: translatedTxt === quiz.goodWord.translatedTxt onIncorrectlyPressed: { // push the error to have it asked again QuizActivity.remainingWords.unshift(quiz.goodWord); QuizActivity.nextSubLevelQuiz(); } onCorrectlyPressed: { QuizActivity.nextSubLevelQuiz(); } } } } } BarButton { id: repeatItem source: "qrc:/gcompris/src/core/resource/bar_repeat.svg"; sourceSize.width: 80 * ApplicationInfo.ratio z: 12 anchors { top: parent.top left: parent.left margins: 10 * ApplicationInfo.ratio } onClicked: Activity.playWord(goodWord.voice) Behavior on opacity { PropertyAnimation { duration: 200 } } } Score { id: score parent: quiz anchors.bottom: undefined anchors.bottomMargin: 10 * ApplicationInfo.ratio anchors.right: parent.right anchors.rightMargin: 10 * ApplicationInfo.ratio anchors.top: parent.top - anchors.left: imageFrame.right } Bonus { id: bonus onWin: imageReview.nextMiniGame() } } }