feat: dynamische Cookie-Bilder je nach Liste

- Füge listenspezifische PNGs hinzu (famous quotes, farmer wisdom, UNfortune, idioms, sandman, unicorn, vegan recipes)
- Implementiere dynamische Bildauswahl basierend auf currentFortuneListName
- Cookie-Bild aktualisiert sich sofort beim Start und Listenwechsel
- Bereinige Cookie-Icon-Größen für einheitliches Aussehen (34x30 / 30x26 GU)
- Entferne Spruchanzahl in Klammern aus Listenbeschreibungen
- Füge Switch für Cookie-Knacksgeräusch (cookieCrackEnabled) in Einstellungen hinzu
- Optimierte updateCookieImage()-Funktion mit expliziten Aufrufen bei allen Zustandsänderungen

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
darklithium
2026-06-06 02:36:14 +02:00
parent 8586e38bb4
commit 8f9dc7f1a6
16 changed files with 154 additions and 13 deletions
+98
View File
@@ -0,0 +1,98 @@
# Lektionen gelehrt am 06.06.2026
## 🎯 Dynamische Cookie-Bilder Implementierung
### Problem
Cookie-Bilder sollten sich je nach ausgewählter Spruchliste ändern (z.B. `famous quotes_open.png` für berühmte Zitate).
### Lösung
1. **Funktion `updateCookieImage()`** erstellt, die den Bildpfad basierend auf `currentFortuneListName` und `fortuneOpened` bestimmt
2. **Explizite Aufrufe** an allen Stellen, wo sich der Zustand ändert:
- Initialisierung (mit `Qt.callLater` für UI-Bereitschaft)
- Beim Listenwechsel in den Einstellungen
- Beim Öffnen/Schließen des Cookies (MouseArea Handler)
- Beim Neuladen des Fortunes
### Wichtige Erkenntnis
**Qt.binding() funktioniert NICHT zuverlässig** für automatische Updates, wenn sich Properties in JavaScript-Funktionen ändern.
**Immer explizite Aufrufe** von Update-Funktionen verwenden, statt auf automatische Bindings zu vertrauen.
### Code-Beispiel
```qml
function updateCookieImage() {
var listName = currentFortuneListName || "fortune";
var availableLists = ["farmer wisdom", "UNfortune", ...];
if (availableLists.indexOf(listName) !== -1) {
var encodedName = listName.replace(/ /g, "%20");
cookieImage.source = Qt.resolvedUrl("../assets/" + encodedName + (fortuneOpened ? "_open.png" : "_close.png"));
} else {
cookieImage.source = fortuneOpened ? Qt.resolvedUrl("../assets/cookie_open2.png") : Qt.resolvedUrl("../assets/cookie_closed2.png");
}
}
```
---
## 📝 Listenbeschreibungen
### Problem
Spruchanzahl wurde in Klammern angezeigt (z.B. "Redensarten aus aller Welt (15)").
### Lösung
`cleanDescription()`-Funktion entfernt alle Klammern mit Zahlen am Ende:
```qml
function cleanDescription(text) {
return text.replace(/\s*\(\d+\)$/, "");
}
```
---
## 🔊 Cookie-Knacksgeräusch Toggle
### Implementierung
- Property `cookieCrackEnabled` (default: true)
- Switch in Einstellungen mit Binding an die Property
- Sound wird nur abgespielt, wenn `cookieCrackEnabled === true`
### Code
```qml
Switch {
checked: cookieCrackEnabled
onCheckedChanged: {
cookieCrackEnabled = checked;
py.call("fortunecookie.set_cookie_crack_enabled", [checked]);
}
}
// In Event-Handlern:
if (cookieCrackEnabled) crackMediaPlayer.play();
```
---
## 📏 Cookie-Icon-Größen
### Anpassung
- Geschlossen: 30x26 GU
- Geöffnet: 34x30 GU
Alle Cookie-Bilder haben jetzt ähnliche Dimensionen für ein einheitliches Aussehen.
---
## 🔧 Debugging-Tipps
1. **console.log() ist essenziell** - Ohne Debug-Ausgaben ist es schwer, den Code-Fluss zu verfolgen
2. **Clean Build** - `clickable clean` vor `clickable build` durchführen, wenn Änderungen nicht sichtbar sind
3. **Git Status prüfen** - `git status` zeigt, welche Dateien geändert sind
4. **Build-Directory prüfen** - Manchmal wird die alte Main.qml verwendet, weil der Build nicht neu gestartet wurde
---
## 📌 Best Practices
1. **Explizit > Implizit** - Bei QML besser explizite Funktionsaufrufe als automatische Bindings verwenden
2. **Fehlerbehandlung** - try-catch in komplexen Funktionen hilft bei der Fehlersuche
3. **Konsistente Größen** - UI-Elemente sollten ähnliche Dimensionen haben für ein professionelles Aussehen
4. **Benutzerfreundlichkeit** - Toggle-Switches für Sound sind intuitiver als Checkboxen
Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 309 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 305 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 307 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 281 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 280 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 262 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 333 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 354 KiB

+56 -13
View File
@@ -19,8 +19,26 @@ MainView {
property bool fortuneOpened: false
property string currentFortune: ""
property bool musicPlaying: false
property bool cookieCrackEnabled: true
property bool appInitialized: false
property string currentFortuneListDescription: ""
property string currentFortuneListName: ""
function updateCookieImage() {
var listName = currentFortuneListName || "fortune";
var availableLists = ["farmer wisdom", "UNfortune", "sandman", "famous quotes", "idioms", "vegan recipes", "unicorn"];
if (availableLists.indexOf(listName) !== -1) {
var encodedName = listName.replace(/ /g, "%20");
cookieImage.source = Qt.resolvedUrl("../assets/" + encodedName + (fortuneOpened ? "_open.png" : "_close.png"));
} else {
cookieImage.source = fortuneOpened ? Qt.resolvedUrl("../assets/cookie_open2.png") : Qt.resolvedUrl("../assets/cookie_closed2.png");
}
}
// Entfernt Spruchanzahl in Klammern aus Beschreibung (z.B. "Text (15)" → "Text")
function cleanDescription(text) {
return text.replace(/\s*\(\d+\)$/, "");
}
Python {
id: py
@@ -94,20 +112,25 @@ MainView {
py.call("fortunecookie.get_initial_fortune", [], function(result) {
currentFortune = result;
currentFortuneLabel.text = currentFortune;
cookieImage.source = Qt.resolvedUrl("../assets/cookie_closed2.png");
});
// Musik-Status laden
py.call("fortunecookie.get_music_enabled", [], function(result) {
musicPlaying = result;
console.log("DEBUG QML: musicPlaying geladen: " + musicPlaying);
if (musicPlaying) {
mediaPlayer.play();
}
});
// Cookie-Crack-Sound-Status laden (lokal gespeichert)
py.call("fortunecookie.get_cookie_crack_enabled", [], function(result) {
root.cookieCrackEnabled = (result !== false && result !== undefined); // Default: true
});
// Aktuelle Liste laden und Beschreibung setzen
py.call("fortunecookie.get_current_fortune_list", [], function(listName) {
root.currentFortuneListName = listName;
Qt.callLater(function() { updateCookieImage(); });
var descriptions = {
"fortune": "klassische Glückskeks-Sprüche",
"farmer wisdom": "Bauernweisheiten",
@@ -118,7 +141,7 @@ MainView {
"vegan recipes": "Vegane Rezeptideen",
"unicorn": "Einhorn Glückssprüche (die fast schon wehtun)"
};
root.currentFortuneListDescription = descriptions[listName] || listName;
root.currentFortuneListDescription = cleanDescription(descriptions[listName] || listName);
});
appInitialized = true;
@@ -132,9 +155,9 @@ MainView {
Image {
id: cookieImage
anchors.centerIn: parent
width: fortuneOpened ? units.gu(36) : units.gu(32)
height: fortuneOpened ? units.gu(28) : units.gu(24)
source: fortuneOpened ? Qt.resolvedUrl("../assets/cookie_open2.png") : Qt.resolvedUrl("../assets/cookie_closed2.png")
width: fortuneOpened ? units.gu(34) : units.gu(30)
height: fortuneOpened ? units.gu(30) : units.gu(26)
source: ""
fillMode: Image.PreserveAspectFit
MouseArea {
@@ -146,13 +169,13 @@ MainView {
onReleased: {
if (mouseY < startY - units.gu(2)) {
py.call("fortunecookie.open_fortune", [], function() {
crackMediaPlayer.play();
if (cookieCrackEnabled) crackMediaPlayer.play();
fortuneOpened = true;
updateCookieImage();
py.call("fortunecookie.get_current_fortune", [], function(result) {
currentFortune = result;
currentFortuneLabel.text = currentFortune;
currentFortuneLabel.visible = true;
cookieImage.source = Qt.resolvedUrl("../assets/cookie_open2.png");
});
});
}
@@ -166,20 +189,20 @@ MainView {
onClicked: {
if (!fortuneOpened) {
py.call("fortunecookie.open_fortune", [], function() {
crackMediaPlayer.play();
if (cookieCrackEnabled) crackMediaPlayer.play();
fortuneOpened = true;
updateCookieImage();
py.call("fortunecookie.get_current_fortune", [], function(result) {
currentFortune = result;
currentFortuneLabel.text = currentFortune;
currentFortuneLabel.visible = true;
cookieImage.source = Qt.resolvedUrl("../assets/cookie_open2.png");
});
});
} else {
fortuneOpened = false;
updateCookieImage();
currentFortuneLabel.text = "";
currentFortuneLabel.visible = false;
cookieImage.source = Qt.resolvedUrl("../assets/cookie_closed2.png");
}
}
}
@@ -207,10 +230,10 @@ MainView {
onClicked: {
py.call("fortunecookie.get_new_fortune", [], function() {
fortuneOpened = false;
updateCookieImage();
py.call("fortunecookie.get_current_fortune", [], function(result) {
currentFortune = result;
currentFortuneLabel.text = currentFortune;
cookieImage.source = Qt.resolvedUrl("../assets/cookie_closed2.png");
});
});
}
@@ -332,13 +355,33 @@ MainView {
var newList = newListObj ? newListObj.list_name : "fortune";
py.call("fortunecookie.set_fortune_list", [newList], function() {
console.log("Spruchliste gewaehlt: " + newList);
root.currentFortuneListName = newList;
updateCookieImage();
reloadFortune();
// Aktualisiere die Anzeige im Hauptbildschirm
root.currentFortuneListDescription = newListObj ? newListObj.description : "";
root.currentFortuneListDescription = newListObj ? cleanDescription(newListObj.description) : "";
});
}
}
// COOKIE-CRACK-SOUND TOGGLE
Label {
text: "Cookie-Knacksgeräusch:"
Layout.fillWidth: true
fontSize: "large"
}
Switch {
id: crackSoundSwitch
Layout.fillWidth: false
Layout.alignment: Qt.AlignHCenter
checked: cookieCrackEnabled
onCheckedChanged: {
cookieCrackEnabled = checked;
py.call("fortunecookie.set_cookie_crack_enabled", [checked]);
}
}
// ZURÜCK-BUTTON
Item {
Layout.fillWidth: true