1/* GCompris - lang.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 "qrc:/gcompris/src/core/core.js" as Core
20
21Item {
22    id: imageReview
23    anchors.fill: parent
24
25    property alias category: categoryText.text
26    property int wordListIndex // This is the current sub list of words
27    property var word: rootItem.opacity == 1 ? items.wordList[wordListIndex][score.currentSubLevel - 1] : undefined
28    // miniGames is list of miniGames
29    // first element is Activity name,
30    // second element is mode of miniGame
31    // third element is the qml to load
32    property var miniGames: [
33        ["QuizActivity", 1, "Quiz.qml"],
34        ["QuizActivity", 2, "Quiz.qml"],
35        ["QuizActivity", 3, "Quiz.qml"],
36        ["SpellActivity", 1, "SpellIt.qml"]
37    ]
38    property var currentMiniGame
39    property var loadedItems
40    property bool started: rootItem.opacity == 1
41
42    // Start at last wordListIndex
43    function start() {
44        initLevel(wordListIndex)
45    }
46
47    // Start the image review at wordList sublesson
48    function initLevel(wordListIndex_) {
49        wordListIndex = wordListIndex_
50        score.currentSubLevel = 1
51        score.numberOfSubLevels = items.wordList[wordListIndex].length
52        focus = true
53        forceActiveFocus()
54        miniGameLoader.source = ""
55        currentMiniGame = -1
56        rootItem.opacity = 1
57    }
58
59    function restoreMinigameFocus() {
60        miniGameLoader.item.restoreFocus();
61    }
62
63    function stop() {
64        focus = false
65        rootItem.opacity = 0
66        wordImage.changeSource('')
67        wordText.changeText('')
68        repeatItem.visible = false
69    }
70
71    onWordChanged: {
72        if(word) {
73            if (Activity.playWord(word.voice)) {
74                word['hasVoice'] = true
75                repeatItem.visible = true
76            } else {
77                word['hasVoice'] = false
78                repeatItem.visible = false
79            }
80            wordImage.changeSource(word.image)
81            wordText.changeText(word.translatedTxt)
82        }
83    }
84
85    //    Cheat codes to access mini games directly
86    Keys.onPressed: {
87        if((event.modifiers & Qt.ControlModifier) && (event.key === Qt.Key_1)) {
88            initLevel(wordListIndex)
89            event.accepted = true
90        }
91        if((event.modifiers & Qt.ControlModifier) && (event.key === Qt.Key_2)) {
92            startMiniGame(0)
93            event.accepted = true
94        }
95        if((event.modifiers & Qt.ControlModifier) && (event.key === Qt.Key_3)) {
96            startMiniGame(1)
97            event.accepted = true
98        }
99        if((event.modifiers & Qt.ControlModifier) && (event.key === Qt.Key_4)) {
100            startMiniGame(2)
101            event.accepted = true
102        }
103        if((event.modifiers & Qt.ControlModifier) && (event.key === Qt.Key_5)) {
104            startMiniGame(3)
105            event.accepted = true
106        }
107    }
108
109    Keys.onEscapePressed: {
110        Activity.launchMenuScreen()
111    }
112
113    Keys.onLeftPressed: {
114        if( score.currentSubLevel > 1 ) {
115            imageReview.prevWord()
116            event.accepted = true
117        }
118    }
119    Keys.onRightPressed: {
120        imageReview.nextWord()
121        event.accepted = true
122    }
123    Keys.onSpacePressed: {
124        imageReview.nextWord()
125        event.accepted = true
126    }
127    Keys.onEnterPressed: {
128        imageReview.nextWord()
129        event.accepted = true
130    }
131    Keys.onReturnPressed: {
132        imageReview.nextWord()
133        event.accepted = true
134    }
135    Keys.onTabPressed: {
136        repeatItem.clicked()
137    }
138
139    Keys.onReleased: {
140        if (event.key === Qt.Key_Back) {
141            event.accepted = true
142            Activity.launchMenuScreen()
143        }
144    }
145
146    Item {
147        id: rootItem
148        anchors.fill: parent
149        opacity: 0
150        Behavior on opacity { PropertyAnimation { duration: 200 } }
151
152        Rectangle {
153            id: categoryTextbg
154            parent: rootItem
155            x: categoryText.x - 4
156            y: categoryText.y - 4
157            width: imageFrame.width + 8
158            height: categoryText.height + 8
159            color: "#5090ff"
160            border.color: "#000000"
161            border.width: 2
162            radius: 16
163            anchors {
164                horizontalCenter: parent.horizontalCenter
165                top: rootItem.top
166                topMargin: 4 * ApplicationInfo.ratio
167            }
168
169            GCText {
170                id: categoryText
171                fontSize: mediumSize
172                font.weight: Font.DemiBold
173                width: parent.width - 8
174                horizontalAlignment: Text.AlignHCenter
175                verticalAlignment: Text.AlignVCenter
176                color: "white"
177                wrapMode: Text.WordWrap
178            }
179        }
180
181        Image {
182            id: imageFrame
183            parent: rootItem
184            source: "qrc:/gcompris/src/activities/lang/resource/imageid_frame.svg"
185            width: (parent.width - previousWordButton.width * 2) * 0.8
186            height: (parent.height - categoryTextbg.height - wordTextbg.height - bar.height * 1.1) * 0.8
187            sourceSize.width: width
188            fillMode: Image.PreserveAspectFit
189            anchors {
190                horizontalCenter: parent.horizontalCenter
191                top: categoryTextbg.bottom
192                margins: 10 * ApplicationInfo.ratio
193            }
194            z: 11
195
196            Image {
197                id: wordImage
198                // Images are not svg
199                width: parent.paintedHeight * 0.9
200                height: width
201                anchors.centerIn: parent
202
203                property string nextSource
204                function changeSource(nextSource_) {
205                    nextSource = nextSource_
206                    animImage.restart()
207                }
208
209                SequentialAnimation {
210                    id: animImage
211                    PropertyAnimation {
212                        target: wordImage
213                        property: "opacity"
214                        to: 0
215                        duration: 100
216                    }
217                    PropertyAction {
218                        target: wordImage
219                        property: "source"
220                        value: wordImage.nextSource
221                    }
222                    PropertyAnimation {
223                        target: wordImage
224                        property: "opacity"
225                        to: 1
226                        duration: 100
227                    }
228                }
229                MouseArea {
230                    anchors.fill: parent
231                    enabled: rootItem.opacity == 1
232                    onClicked: Activity.playWord(word.voice)
233                }
234            }
235
236            Image {
237                id: previousWordButton
238                source: "qrc:/gcompris/src/core/resource/bar_previous.svg";
239                sourceSize.width: 30 * 1.2 * ApplicationInfo.ratio
240                visible: score.currentSubLevel > 1 ? true : false
241                anchors {
242                    right: parent.left
243                    rightMargin: 30
244                    top: parent.top
245                    topMargin: parent.height/2 - previousWordButton.height/2
246                }
247                MouseArea {
248                    id: previousWordButtonArea
249                    anchors.fill: parent
250                    onClicked: imageReview.prevWord()
251                }
252            }
253
254            Image {
255                id: nextWordButton
256                source: "qrc:/gcompris/src/core/resource/bar_next.svg";
257                sourceSize.width: 30 * 1.2 * ApplicationInfo.ratio
258                anchors {
259                    left: parent.right
260                    leftMargin: 30
261                    top: parent.top
262                    topMargin: parent.height/2 - previousWordButton.height/2
263                }
264                MouseArea {
265                    id: nextWordButtonArea
266                    anchors.fill: parent
267                    onClicked: imageReview.nextWord();
268                }
269            }
270        }
271
272        Rectangle {
273            id: wordTextbg
274            parent: rootItem
275            x: wordText.x - 4
276            y: wordText.y - 4
277            width: imageFrame.width
278            height: wordText.height + 4
279            color: "#5090ff"
280            border.color: "#000000"
281            border.width: 2
282            radius: 16
283            anchors {
284                top: imageFrame.bottom
285                left: imageFrame.left
286                margins: 10 * ApplicationInfo.ratio
287            }
288
289            GCText {
290                id: wordText
291                text: ""
292                fontSize: largeSize
293                font.weight: Font.DemiBold
294                width: parent.width
295                horizontalAlignment: Text.AlignHCenter
296                verticalAlignment: Text.AlignVCenter
297                color: "white"
298                wrapMode: Text.WordWrap
299
300                property string nextWord
301                function changeText(nextWord_) {
302                    nextWord = nextWord_
303                    animWord.restart()
304                }
305
306                SequentialAnimation {
307                    id: animWord
308                    PropertyAnimation {
309                        target: wordText
310                        property: "opacity"
311                        to: 0
312                        duration: 100
313                    }
314                    PropertyAction {
315                        target: wordText
316                        property: "text"
317                        value: wordText.nextWord
318                    }
319                    PropertyAnimation {
320                        target: wordText
321                        property: "opacity"
322                        to: 1
323                        duration: 100
324                    }
325                }
326            }
327        }
328
329        BarButton {
330            id: repeatItem
331            parent: rootItem
332            source: "qrc:/gcompris/src/core/resource/bar_repeat.svg";
333            sourceSize.width: Math.min(imageFrame.x, 100 * ApplicationInfo.ratio) - 2 * anchors.margins
334
335            z: 12
336            anchors {
337                top: parent.top
338                left: parent.left
339                margins: 10 * ApplicationInfo.ratio
340            }
341            onClicked: Activity.playWord(imageReview.word.voice)
342            Behavior on opacity { PropertyAnimation { duration: 200 } }
343        }
344
345        Score {
346            id: score
347            parent: rootItem
348        }
349    }
350    Loader {
351        id: miniGameLoader
352        width: parent.width
353        height: parent.height
354        anchors.fill: parent
355        asynchronous: false
356    }
357
358    function nextPressed() {
359        if(currentMiniGame === 0) {
360            nextSubLevel()
361        }
362    }
363
364    function nextWord() {
365        ++score.currentSubLevel;
366
367        if(score.currentSubLevel == score.numberOfSubLevels + 1) {
368            nextMiniGame()
369        }
370    }
371
372    function prevWord() {
373        --score.currentSubLevel
374    }
375
376    function startMiniGame(miniGameIndex) {
377        currentMiniGame = miniGameIndex
378        var mode = miniGames[miniGameIndex][1];
379        var itemToLoad = miniGames[miniGameIndex][2];
380
381        // Starting a minigame we don't want pending voices to play
382        Activity.clearVoiceQueue()
383
384        // preparing the wordList
385        var wordList = Core.shuffle(items.wordList[wordListIndex]).slice()
386
387        miniGameLoader.source = itemToLoad;
388        var loadedItems = miniGameLoader.item
389
390        rootItem.opacity = 0
391        focus = false
392
393        // Initiate the loaded item mini game
394        // Some Mini Games may not start because they miss voices
395        // In this case we try the next one
396        if(!loadedItems.init(loadedItems, wordList, mode))
397            nextMiniGame()
398    }
399
400    //called by a miniGame when it is won
401    function nextMiniGame() {
402        if(currentMiniGame < miniGames.length - 1) {
403            startMiniGame(++currentMiniGame)
404        } else {
405            Activity.markProgress()
406            if(wordListIndex < items.wordList.length - 1) {
407                initLevel(wordListIndex + 1)
408            } else {
409                Activity.launchMenuScreen()
410                miniGameLoader.source = ""
411            }
412        }
413    }
414}
415