diff --git a/src/activities/explore_farm_animals/AnimalLevels.qml b/src/activities/explore_farm_animals/AnimalLevels.qml index 13269e4a2..9c052a503 100644 --- a/src/activities/explore_farm_animals/AnimalLevels.qml +++ b/src/activities/explore_farm_animals/AnimalLevels.qml @@ -1,116 +1,116 @@ /* GCompris - AnimalLevels.qml * * Copyright (C) 2015 Ayush Agrawal * * Authors: * Beth Hadley (GTK+ version) * Ayush Agrawal (Qt Quick port) * Djalil MESLI (Qt Quick port) * Johnny Jazeix (Qt Quick port) * * 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.6 import GCompris 1.0 import "../../core" import "explore-level.js" as Activity Image { id: animalImg width: animalWidth height: animalHeight sourceSize.width: width sourceSize.height: height fillMode: Image.PreserveAspectFit property string name: name property alias starVisible: star.visible property int questionId property string title property string description property string imageSource property string question property string audio signal displayDescription(var animal) SequentialAnimation { id: anim running: true loops: 1 NumberAnimation { target: animalImg property: "rotation" from: 0; to: 360 duration: 400 + Math.floor(Math.random() * 400) easing.type: Easing.InOutQuad } } Image { id: star x: animalImg.width / 2.5 y: animalImg.height * 0.8 visible: false source:"qrc:/gcompris/src/core/resource/star.png" } MultiPointTouchArea { id: touchArea anchors.centerIn: parent // Make the item big enough to be clicked easily width: Math.max(parent.width, 55 * ApplicationInfo.ratio) height: Math.max(parent.height, 55 * ApplicationInfo.ratio) touchPoints: [ TouchPoint { id: point1 } ] - mouseEnabled: progressbar.value != progressbar.maximumValue + mouseEnabled: progressbar.value != progressbar.maximumValue && !items.bonus.isPlaying onPressed: { if(items.progressbar.value >= progressbar.maximumValue) { return } var questionTargetId = items.questionOrder[Activity.items.progressbar.value] Activity.items.instruction.visible = false if (Activity.items.score.currentSubLevel == 1) { audioVoices.play(animalImg.audio); displayDescription(animalImg) star.visible = true; } else { if (questionId === questionTargetId) { animWin.start(); items.progressbar.value ++; Activity.nextSubSubLevel(); } else { items.bonus.bad("smiley") } } } } SequentialAnimation { id: animWin running: false loops: 1 NumberAnimation { target: animalImg property: "rotation" from: 0; to: 360 duration: 600 easing.type: Easing.InOutQuad } } } diff --git a/src/core/Bonus.qml b/src/core/Bonus.qml index 583a5ad6f..0bb27a9a7 100644 --- a/src/core/Bonus.qml +++ b/src/core/Bonus.qml @@ -1,197 +1,203 @@ /* GCompris - Bonus.qml * * Copyright (C) 2014 Bruno Coudoin * * Authors: * Bruno Coudoin * * 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.6 import GCompris 1.0 // Requires the global property in the scope: // property GCAudio audioEffects, audioVoices /** * A QML component providing user feedback upon winning/loosing. * @ingroup components * * Usually triggered by an activity when a user has won/lost a level via the * @ref good / @ref bad methods. Bonus then provides visual and auditive * feedback to the user and emits the @ref win / @ref loose signals when * finished. * * Maintains a list of possible audio voice resources to be playebd back * upon winning/loosing events, and selects randomly from them when triggered. * * @inherit QtQuick.Image */ Image { id: bonus /** * type:string * Url of the audio resource to be used as winning sound. */ property string winSound: url + "sounds/bonus.wav" /** * type:string * Url of the audio resource to be used as loosing sound. */ property string looseSound /** * type:int * Interval in milliseconds after which the bonus will be played (default is 500ms) */ property alias interval: timer.interval /** * Emitted when the bonus starts */ signal start /** * Emitted when the bonus stops */ signal stop /** * Emitted when the win event is over. * * After the animation has finished. */ signal win /** * Emitted when the loose event is over. * * After the animation has finished. */ signal loose /// @cond INTERNAL_DOCS property string url: "qrc:/gcompris/src/core/resource/" property bool isWin: false property var winVoices: [ "voices-$CA/$LOCALE/misc/congratulation.$CA", "voices-$CA/$LOCALE/misc/great.$CA", "voices-$CA/$LOCALE/misc/good.$CA", "voices-$CA/$LOCALE/misc/awesome.$CA", "voices-$CA/$LOCALE/misc/fantastic.$CA", "voices-$CA/$LOCALE/misc/waytogo.$CA", "voices-$CA/$LOCALE/misc/super.$CA", "voices-$CA/$LOCALE/misc/perfect.$CA" ] property var looseVoices: [ "voices-$CA/$LOCALE/misc/check_answer.$CA" ] /// @endcond + /** + * type:bool + * True between the moment we have the win/lose signal emitted and the + * bonus image is no more displayed + */ + property bool isPlaying: animation.running || timer.running visible: true opacity: 0 anchors.fill: parent anchors.margins: 50 * ApplicationInfo.ratio fillMode: Image.PreserveAspectFit z: 1000 sourceSize.width: parent.width * 0.5 /** * Triggers win feedback. * * Tries to play back a voice resource for winning, if not found fall back * to the winSound. * * @param name Type of win image to show. * Possible values are "flower", "gnu", "lion", "note", "smiley", "tux" */ function good(name) { source = url + "bonus/" + name + "_good.svg" isWin = true timer.start() } /** * Triggers loose feedback. * * Tries to play back a voice resource for loosing, if not found fall back * to the looseSound. * * @param name Type of win image to show. * Possible values are "flower", "gnu", "lion", "note", "smiley", "tux" */ function bad(name) { source = url + "bonus/" + name + "_bad.svg" isWin = false; timer.start() } /** * Private: Triggers win feedback after the timer completion */ function _good() { if(!audioVoices.play( ApplicationInfo.getAudioFilePath( winVoices[Math.floor(Math.random()*winVoices.length)]))) if(winSound) audioEffects.play(winSound) start() animation.start() } /** * Private: Triggers loose feedback after the timer completion. */ function _bad(name) { if(!audioEffects.play( ApplicationInfo.getAudioFilePath( looseVoices[Math.floor(Math.random()*looseVoices.length)]))) if(looseSound) audioEffects.play(looseSound) start() animation.start() } SequentialAnimation { id: animation NumberAnimation { target: bonus property: "opacity" from: 0; to: 1.0 duration: 1000 easing.type: Easing.InOutQuad } NumberAnimation { target: bonus property: "opacity" from: 1.0; to: 0 duration: 500 easing.type: Easing.InOutQuad } onStopped: { bonus.stop() isWin ? win() : loose() } } // It is useful to launch the bonus after a delay to let the children // appreciate the completed level Timer { id: timer interval: 500 onTriggered: isWin ? bonus._good() : bonus._bad() } }