JLearner All functionality

This commit is contained in:
Hannes
2026-03-07 23:44:27 +01:00
parent f202619644
commit 546111c46c
7 changed files with 633 additions and 172 deletions
+89 -44
View File
@@ -15,6 +15,11 @@ PanelWindow {
visible: true
focusable: true
Component.onCompleted: {
semiJLoader.all_invisible()
languageChooser.visible = true
}
FocusScope {
id: jLearnerScope
focus: true
@@ -35,60 +40,100 @@ PanelWindow {
Rectangle {
anchors.fill: parent
radius: 10
color: Qt.alpha(Colors.surfaceContainerLowest, 0.5)
// color: Qt.alpha(Colors.surfaceContainerLowest, 0.5)
color: "blue"
border.width: 2
border.color: Colors.outlineVariant
clip: true
Column {
id: window
anchors.fill: parent
spacing: 10
Rectangle{
width: parent.width - 20
height: parent.height - 20
anchors.centerIn: parent
color: "pink"
Rectangle {
id: head
width: window.width
height: window.height * 0.1
color: "#FFFFFF"
Column {
id: learnerWindow
anchors.fill: parent
spacing: 10
Text {
text: "Language Learner"
anchors.centerIn: parent
font.pixelSize: 48
color: "black"
Rectangle {
id: head
width: parent.width
height: parent.height * 0.1
color: "#FFFFFF"
Text {
text: "Language Learner"
anchors.centerIn: parent
font.pixelSize: parent.height * 0.8
color: "black"
}
}
Rectangle{
id: semiJLoader
width: parent.width
height: parent.height * 0.9 - parent.spacing
color: "orange"
function all_invisible() {
languageChooser.visible = false
kanaVoicing.visible = false
voicingKana.visible = false
learnerResult.visible = false
}
function switchModeChooser() {
all_invisible()
languageChooser.visible = true
languageChooser.start()
}
function switch_KanaVoicing() {
all_invisible()
kanaVoicing.visible = true
kanaVoicing.start()
}
function switch_VoicingKana() {
all_invisible()
voicingKana.visible = true
voicingKana.start()
}
function switchResult(result, mode, results) {
all_invisible()
console.log("Result: " + result)
console.log("Mode: " + mode)
learnerResult.visible = true
learnerResult.result = result
learnerResult.mode = mode
learnerResult.results = results
learnerResult.start()
}
ModeChooser {
id: languageChooser
}
KanaVoicing {
id: kanaVoicing
}
VoicingKana {
id: voicingKana
}
JLearnerResult {
id: learnerResult
}
}
}
function switch_KanaVoicing() {
languageChooser.visible = false
kanaVoicing.visible = true
}
function switchModeChooser() {
languageChooser.visible = true
kanaVoicing.visible = false
}
function switchResult(result) {
console.log("Result: " + result)
languageChooser.visible = true
kanaVoicing.visible = false
}
ModeChooser {
id: languageChooser
}
KanaVoicing {
id: kanaVoicing
}
// KanaVoicing {
// id: kanaVoicing
// }
}
}
}
+255
View File
@@ -0,0 +1,255 @@
import QtQuick
import QtQuick.Controls
import "../../../colors"
Item { // Chooser
id: learnerResult
width: parent.width
height: parent.height
anchors.margins: 15
visible: false
function switch_KanaVoicing() {
parent.switch_KanaVoicing()
}
function start() {
}
property real result: 0
property string mode: ""
property var results: createResults(10)
function createResults(n) {
var arr = []
for (var i = 0; i < n; i++) {
arr.push({
kana: "あ",
correctness: false,
answer: "a",
correct: "a"
})
}
return arr
}
Column {
anchors.fill: parent
spacing: 10
Rectangle {
id: learnerResultUpperText
color: "#FFFFFF"
width: parent.width
height: parent.height * 0.1
Text {
id: mainText
text: "Ergebnisse:"
anchors.centerIn: parent
font.pixelSize: parent.height * 0.6
color: "black"
}
}
Row {
width: parent.width
height: parent.height - learnerResultUpperText.height - parent.spacing
spacing: 10
Rectangle {
width: parent.width * 0.25
height: parent.height
color: "transparent"
Column{
width: parent.width
height: parent.height
spacing: 10
Repeater{
model: results
Row{
width: parent.width
height: parent.height/10 - parent.spacing * 0.9
spacing: 10
Rectangle{
width: parent.height
height: parent.height
color: "white"
Text{
text: modelData.kana
width: parent.width
height: parent.height
anchors.centerIn: parent
anchors.verticalCenterOffset: -parent.height * 0.125
font.pixelSize: parent.height * 0.8
color: modelData.correctness ? "green" : "red"
}
}
Rectangle{
width: parent.height
height: parent.height
color: "white"
Image {
source: modelData.correctness ? "../../../colors/icons/correct.svg" : "../../../colors/icons/wrong.svg"
anchors.centerIn: parent
width: parent.height*0.8
height: parent.height*0.8
smooth: true
sourceSize.width: width
sourceSize.height: height
}
}
Rectangle{
width: parent.width - parent.height *2 - parent.spacing*2
height: parent.height
color: "white"
Text{
text: "[" + modelData.correct + "]"
width: parent.width
height: parent.height
anchors.centerIn: parent
anchors.horizontalCenterOffset: 10
font.pixelSize: parent.height * 0.8
color: modelData.correctness ? "green" : "red"
}
}
}
}
}
}
Rectangle{
width: parent.width * 0.75
height: parent.height
color: "transparent"
Column{
width: parent.width
height: parent.height
spacing: 10
Row {
spacing: 10
width: parent.width
height: parent.height * 4 / 10 - parent.spacing * 2 / 3
Rectangle {
color: "transparent"
width: (parent.width - (learnerLastResultKanaBG.width + learnerLastResultTextBG.width))/2
height: parent.height
}
Rectangle {
id: learnerLastResultKanaBG
color: "#FFFFFF"
width: parent.height - parent.spacing
height: parent.height
Text {
id: learnerLastResultKana
text: results[results.length-1].kana
width: parent.width
height: parent.height
anchors.centerIn: parent
anchors.verticalCenterOffset: -parent.height * 0.1
font.pixelSize: parent.height * 0.8
color: results[results.length-1].correctness ? "green" : "red"
}
}
Rectangle {
id: learnerLastResultTextBG
color: "#FFFFFF"
width: learnerLastResultText.width + 2 * parent.spacing
height: parent.height
Text {
id: learnerLastResultText
text: "[" + results[results.length-1].correct + "]"
anchors.centerIn: parent
font.pixelSize: learnerLastResultKana.font.pixelSize/2
color: results[results.length-1].correctness ? "green" : "red"
}
}
}
Rectangle {
id: learnerResultTextBG
color: "#FFFFFF"
width: parent.width
height: parent.height * 3 / 10 - parent.spacing * 2 / 3
Text {
id: learnerResultText
text: result*100 + "% Richtig"
width: parent.width
horizontalAlignment: Text.AlignHCenter
font.pixelSize: Math.min(parent.width / text.length * 1.2, parent.height * 0.8)
color: "black"
}
}
Row {
width: parent.width
height: parent.height * 3 / 10 - parent.spacing * 2 / 3
spacing: 10
MouseArea {
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
width: parent.width / 2 - parent.spacing
height: parent.height
onClicked: {
console.log("Choosing White Window")
mode === "KanaVoicing" ? learnerResult.parent.switch_KanaVoicing() : learnerResult.parent.switch_VoicingKana()
}
Rectangle {
anchors.fill: parent
color: "#FFFFFF"
Text {
text: "Again"
anchors.centerIn: parent
font.pixelSize: Math.min(parent.width / text.length * 1.2, parent.height * 0.8)
color: "black"
}
}
}
MouseArea {
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
width: parent.width / 2 - parent.spacing
height: parent.height
onClicked: {
console.log("Choosing Black Window")
learnerResult.parent.switchModeChooser()
}
Rectangle {
anchors.fill: parent
color: "#000000"
Text {
text: "Menu"
anchors.centerIn: parent
font.pixelSize: Math.min(parent.width / text.length * 1.2, parent.height * 0.8)
color: "white"
}
}
}
}
}
}
}
}
}
+64 -38
View File
@@ -4,12 +4,18 @@ import "../../../colors"
Item { // Kana_Try
id: kanaVoicing
width: window.width
height: window.height - head.height
width: parent.width
height: parent.height
anchors.margins: 15
visible: false
Component.onCompleted: {
// Component.onCompleted: {
// randomKnownKana()
// }
function start() {
kanaVoicingAnswer.focus = true
roundNum = 0
randomKnownKana()
}
@@ -23,10 +29,17 @@ Item { // Kana_Try
property int correct: 0
property int maxRoundNum: 10
property var pastKana: []
property var pastCorrectness: []
function endRounds() {
kanaVoicingAnswer.focus = false
jLearnerScope.focus = true
console.log("Switching back")
roundNum = 0
parent.switchResult(correct/maxRoundNum)
parent.switchResult(correct/maxRoundNum, "KanaVoicing", pastCorrectness)
pastKana = []
pastCorrectness = []
correct = 0
kanaVoicingAnswer.placeholderText = "Type Voicing..."
kanaVoicingAnswerBackground.color = kanaVoicingAnswer.activeFocus ? Colors.tertiary_fg : Colors.primary_fg
}
@@ -37,6 +50,12 @@ Item { // Kana_Try
}
var list = kanaData.kana
currentKana = list[Math.floor(Math.random() * list.length)]
if (knownList.length > maxRoundNum) {
while (pastKana.includes(currentKana)) {
currentKana = list[Math.floor(Math.random() * list.length)]
}
}
pastKana.push(currentKana)
console.log("Round Num: " + roundNum + " - Choosing Kana: " + currentKana.hira)
roundNum = roundNum + 1
}
@@ -47,6 +66,12 @@ Item { // Kana_Try
}
var knownList = kanaData.kana.filter(k => k.known)
currentKana = knownList[Math.floor(Math.random() * knownList.length)]
if (knownList.length > maxRoundNum) {
while (pastKana.includes(currentKana)) {
currentKana = knownList[Math.floor(Math.random() * knownList.length)]
}
}
pastKana.push(currentKana)
console.log("Round Num: " + roundNum + " - Choosing Kana: " + currentKana.hira)
roundNum = roundNum + 1
}
@@ -58,43 +83,33 @@ Item { // Kana_Try
Rectangle {
id: kanaVoicingTextRectangale
color: "#FFFFFF"
width: parent.width
height: kanaVoicingText.height + parent.spacing/2
width: kanaVoicingText.width + 20
height: parent.height * 0.1
anchors.horizontalCenter: parent.horizontalCenter
Text {
id: kanaVoicingText
text: "Im Spiel - Runde: " + kanaVoicing.roundNum
width: parent.width
horizontalAlignment: Text.AlignHCenter
font.pixelSize: 28
anchors.centerIn: parent
font.pixelSize: parent.height * 0.6
color: "black"
}
}
Row {
width: parent.width
height: (parent.height - kanaVoicingTextRectangale.height)*0.8 - parent.spacing*2
spacing: 0
Rectangle {
id: kanaVoicingKanaRectangle
color: "#000000"
height: (parent.height - kanaVoicingTextRectangale.height)*0.75
width: height
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenterOffset: -parent.height * 0.125
Rectangle {
color: "transparent"
width: (parent.width - kanaVoicingKanaRectangle.width)/2
height: parent.height
}
Rectangle {
id: kanaVoicingKanaRectangle
color: "#000000"
width: parent.height
height: parent.height
Text {
id: kanaVoicingKana
text: kanaVoicing.currentKana ? kanaVoicing.currentKana.hira : ""
anchors.centerIn: parent
font.pixelSize: Math.min(parent.width / text.length * 1.2, parent.height * 0.8)
color: "white"
}
Text {
id: kanaVoicingKana
text: typeof kanaVoicing.currentKana.hira === "undefined" ? "" : kanaVoicing.currentKana.hira
anchors.centerIn: parent
font.pixelSize: Math.min(parent.width / text.length * 1.2, parent.height * 0.8)
color: "white"
}
}
@@ -105,8 +120,8 @@ Item { // Kana_Try
anchors.horizontalCenter: parent.horizontalCenter
width: parent.width / 3
height: (parent.height - kanaVoicingTextRectangale.height) * 0.2 - parent.spacing*2
width: parent.width/2
height: (parent.height - kanaVoicingTextRectangale.height)*0.25 - parent.spacing*2
font.pixelSize: height * 0.8
@@ -121,7 +136,7 @@ Item { // Kana_Try
border.width: 1
}
Keys.onReleased: {
Keys.onReleased: function(event) {
if (event.key === Qt.Key_Escape) {
console.log("Escape pressed inside TextField")
console.log("Pressed Escape, closing JLearner")
@@ -137,14 +152,25 @@ Item { // Kana_Try
kanaVoicingAnswer.placeholderText = "[" + kanaVoicing.currentKana.voice + "]"
kanaVoicingAnswerBackground.color = "green"
kanaVoicing.correct = kanaVoicing.correct + 1
randomKnownKana()
pastCorrectness.push({
kana: kanaVoicing.currentKana.hira,
correctness: true,
answer: kanaVoicingAnswer.text.toLowerCase(),
correct: kanaVoicing.currentKana.voice.join("|")
})
} else {
console.log("Wrong: [" + currentKana.voice + "]")
kanaVoicingAnswer.text = ""
kanaVoicingAnswerBackground.color = "red"
kanaVoicingAnswer.placeholderText = "[" + kanaVoicing.currentKana.voice + "]"
randomKnownKana()
pastCorrectness.push({
kana: kanaVoicing.currentKana.hira,
correctness: false,
answer: kanaVoicingAnswer.text.toLowerCase(),
correct: kanaVoicing.currentKana.voice.join("|")
})
}
randomKnownKana()
}
}
}
+14 -18
View File
@@ -4,14 +4,10 @@ import "../../../colors"
Item { // Chooser
id: languageChooser
width: window.width
height: window.height * 0.9
width: parent.width
height: parent.height
anchors.margins: 15
visible: true
function switch_KanaVoicing() {
parent.switch_KanaVoicing()
}
visible: false
Column {
anchors.fill: parent
@@ -20,22 +16,22 @@ Item { // Chooser
Rectangle {
id: modeChooserUpperText
color: "#FFFFFF"
width: parent.width
height: mainText.height + parent.spacing/2
width: mainText.width + 20
height: parent.height * 0.1
anchors.horizontalCenter: parent.horizontalCenter
Text {
id: mainText
text: "Wähle ein Modus"
width: parent.width
horizontalAlignment: Text.AlignHCenter
font.pixelSize: 28
text: "Wähle ein Modus:"
anchors.centerIn: parent
font.pixelSize: parent.height * 0.6
color: "black"
}
}
Row {
width: parent.width
height: parent.height - modeChooserUpperText.height
height: parent.height - modeChooserUpperText.height - parent.spacing
spacing: 10
MouseArea {
@@ -46,7 +42,7 @@ Item { // Chooser
onClicked: {
console.log("Choosing White Window")
languageChooser.switch_KanaVoicing()
languageChooser.parent.switch_KanaVoicing()
}
Rectangle {
@@ -54,7 +50,7 @@ Item { // Chooser
color: "#FFFFFF"
Text {
text: "Weiß"
text: "Kana to Voicing"
anchors.centerIn: parent
font.pixelSize: Math.min(parent.width / text.length * 1.2, parent.height * 0.8)
color: "black"
@@ -70,7 +66,7 @@ Item { // Chooser
onClicked: {
console.log("Choosing Black Window")
languageChooser.switch_KanaVoicing()
languageChooser.parent.switch_VoicingKana()
}
Rectangle {
@@ -78,7 +74,7 @@ Item { // Chooser
color: "#000000"
Text {
text: "Schwarz"
text: "Voicing to Kana"
anchors.centerIn: parent
font.pixelSize: Math.min(parent.width / text.length * 1.2, parent.height * 0.8)
color: "white"
+173 -72
View File
@@ -4,46 +4,121 @@ import "../../../colors"
Item { // Kana_Try
id: voicingKana
width: window.width
height: window.height - head.height
width: parent.width
height: parent.height
anchors.margins: 15
visible: false
Component.onCompleted: {
randomKnownKana()
// Component.onCompleted: {
// randomKnownKana()
// }
function start() {
roundNum = 0
new_round()
}
KanaData {
id: kanaData
}
property var currentKana: []
property int roundNum: 0
property int correct: 0
property int maxRoundNum: 10
function randomKana() {
if (roundNum >= maxRoundNum) {
console.log("Switching back")
roundNum = 0
parent.switchModeChooser()
property var pastKana: []
property var pastCorrectness: []
property var kanaArray: createResults(6)
property var targetKana: kanaArray[Math.floor(Math.random() * kanaArray.length)]
function createResults(n) {
var arr = []
for (var i = 0; i < n; i++) {
arr.push({ hira: "あ", voice: ["a"], known: true })
}
var list = kanaData.kana
currentKana = list[Math.floor(Math.random() * list.length)]
console.log("Round Num: " + roundNum + " - Choosing Kana: " + currentKana.hira)
roundNum = roundNum + 1
return arr
}
function randomKnownKana() {
if (roundNum >= maxRoundNum) {
console.log("Switching back")
roundNum = 0
parent.switchModeChooser()
function new_round() {
roundNum = roundNum + 1
kanaArray = gemerateKanaArray()
targetKana = kanaArray[Math.floor(Math.random() * kanaArray.length)]
console.log("Round Num: " + roundNum + " - Choosing Kana: " + targetKana.hira)
pastKana.push(targetKana)
}
function gemerateKanaArray() {
var arr = []
for (var i = 0; i < 6; i++) {
arr.push(randomKnownKana(arr))
}
return arr
}
function randomKana(arr) {
if (roundNum > maxRoundNum) {
endRounds()
}
var list = kanaData.kana
var newKana = list[Math.floor(Math.random() * list.length)]
var arrExists = Array.isArray(arr)
if (knownList.length > maxRoundNum + 6) {
if (arrExists) {
while (pastKana.includes(newKana) || arr.includes(newKana)) {
newKana = list[Math.floor(Math.random() * list.length)]
}
} else{
while (pastKana.includes(newKana)){
newKana = list[Math.floor(Math.random() * list.length)]
}
}
} else {
if (arrExists) {
while (arr.includes(newKana)) {
newKana = list[Math.floor(Math.random() * list.length)]
}
}
}
kanaArray.push(newKana)
return newKana
}
function randomKnownKana(arr) {
if (roundNum > maxRoundNum) {
endRounds()
}
var knownList = kanaData.kana.filter(k => k.known)
currentKana = knownList[Math.floor(Math.random() * knownList.length)]
console.log("Round Num: " + roundNum + " - Choosing Kana: " + currentKana.hira)
roundNum = roundNum + 1
var newKana = knownList[Math.floor(Math.random() * knownList.length)]
var arrExists = Array.isArray(arr)
if (knownList.length > maxRoundNum + 6) {
if (arrExists) {
while (pastKana.includes(newKana) || arr.includes(newKana)) {
newKana = knownList[Math.floor(Math.random() * knownList.length)]
}
} else{
while (pastKana.includes(newKana)){
newKana = knownList[Math.floor(Math.random() * knownList.length)]
}
}
} else {
if (arrExists) {
while (arr.includes(newKana)) {
newKana = knownList[Math.floor(Math.random() * knownList.length)]
}
}
}
return newKana
}
function endRounds() {
console.log("Switching back")
roundNum = 0
parent.switchResult(correct/maxRoundNum, "VoicingKana", pastCorrectness)
}
Column {
@@ -53,71 +128,97 @@ Item { // Kana_Try
Rectangle {
id: voicingKanaTextRectangale
color: "#FFFFFF"
width: parent.width
height: voicingKanaText.height + parent.spacing/2
width: mainText.width + 20
height: parent.height * 0.1
anchors.horizontalCenter: parent.horizontalCenter
Text {
id: voicingKanaText
text: "Im Spiel - Runde: " + voicingKana.roundNum
width: parent.width
horizontalAlignment: Text.AlignHCenter
font.pixelSize: 28
id: mainText
text: "Runde: " + roundNum + " - [" + targetKana.voice.join("|") + "]:"
anchors.centerIn: parent
font.pixelSize: parent.height * 0.6
color: "black"
}
}
Row {
Rectangle{
width: parent.width
height: parent.height - voicingKanaTextRectangale.height - parent.spacing
spacing: 15
height: parent.height - voicingKanaTextRectangale.height - voicingKanaResultRectangale.height - parent.spacing * 2
color: "transparent"
Grid {
id: grid
anchors.fill: parent
columns: 3
spacing: 10
MouseArea {
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
width: (parent.width - parent.spacing) / 2
height: parent.height
property int rows: 2
onClicked: {
voicingKana.randomKnownKana()
}
// calculate cell width and height based on parent size, spacing, and number of columns/rows
property real cellWidth: (width - (columns - 1) * spacing) / columns
property real cellHeight: (height - (rows - 1) * spacing) / rows
Rectangle {
anchors.fill: parent
color: "#FFFFFF"
Repeater {
model: kanaArray
MouseArea {
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
width: grid.cellWidth
height: grid.cellHeight
Text {
id: voicingKanaKana1
text: voicingKana.currentKana ? voicingKana.currentKana.hira : ""
anchors.centerIn: parent
font.pixelSize: Math.min(parent.width / text.length * 1.2, parent.height * 0.8)
color: "black"
}
}
}
onClicked: {
console.log("Choose a Kana: " + modelData.hira)
if (modelData.hira === targetKana.hira) {
console.log("Correct")
correct = correct + 1
voicingKanaResult.color = "green"
} else {
console.log("Wrong: [" + targetKana.hira + "]")
voicingKanaResult.color = "red"
}
pastCorrectness.push({
kana: targetKana.hira,
correctness: modelData.hira === targetKana.hira,
answer: modelData.hira,
correct: targetKana.voice.join("|")
})
voicingKanaResult.text = "Letzte Runde: " + targetKana.hira + ": " + "[" + targetKana.voice.join("|") + "]"
new_round()
}
MouseArea {
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
width: (parent.width - parent.spacing) / 2
height: parent.height
Rectangle {
width: parent.width
height: parent.height
color: "white"
border.width: 1
radius: 4
onClicked: {
voicingKana.randomKnownKana()
}
Rectangle {
anchors.fill: parent
color: "#000000"
Text {
id: voicingKanaKana2
text: voicingKana.currentKana ? voicingKana.currentKana.hira : ""
anchors.centerIn: parent
font.pixelSize: Math.min(parent.width / text.length * 1.2, parent.height * 0.8)
color: "white"
Text{
text: modelData.hira
anchors.centerIn: parent
anchors.verticalCenterOffset: -parent.height * 0.1
font.pixelSize: parent.height * 0.8
color: "black"
}
}
}
}
}
}
Rectangle {
id: voicingKanaResultRectangale
color: "#FFFFFF"
width: voicingKanaResult.width + 20
height: parent.height * 0.1
anchors.horizontalCenter: parent.horizontalCenter
Text {
id: voicingKanaResult
text: "Wähle das richtige Zeichen"
anchors.centerIn: parent
font.pixelSize: parent.height * 0.6
color: "black"
}
}
}
}