feat: phase 1 - einstellungen mit lautstärke und spruchlisten
- Settings.qml mit Lautstärke-Slidern für Musik und Knack-Geräusch - Spruchlisten-Auswahl (classic, farmer_wisdom, unfortune) - StackLayout für Navigation zwischen Hauptseite und Einstellungen - Python: load_setting/save_setting für generische Einstellungen - Python: Volume-Einstellungen und Spruchlisten-Verwaltung - ASSET_REQUIREMENTS.md für Grafik-Spezifikationen - JSON-Dateien: classic.json, farmer_wisdom.json, unfortune.json Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
+185
-147
@@ -20,6 +20,10 @@ MainView {
|
||||
property bool musicPlaying: false
|
||||
property bool appInitialized: false
|
||||
|
||||
// Medien-Player als globale Properties für Zugriff aus Settings
|
||||
property MediaPlayer globalMediaPlayer: mediaPlayer
|
||||
property MediaPlayer globalCrackPlayer: crackMediaPlayer
|
||||
|
||||
Python {
|
||||
id: py
|
||||
Component.onCompleted: {
|
||||
@@ -44,170 +48,204 @@ MainView {
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
// INITIALISIERUNGS-TIMER
|
||||
// STACK LAYOUT FÜR NAVIGATION
|
||||
// ====================================================================
|
||||
// WICHTIG: PyOtherSide braucht Zeit zum Laden!
|
||||
// 1 Sekunde Verzögerung verhindert Race Conditions
|
||||
Timer {
|
||||
id: initTimer
|
||||
interval: 1000
|
||||
running: true
|
||||
repeat: false
|
||||
onTriggered: {
|
||||
try {
|
||||
currentFortune = py.call_sync("fortunecookie.get_initial_fortune", []);
|
||||
currentFortuneLabel.text = currentFortune;
|
||||
cookieImage.source = Qt.resolvedUrl("../assets/cookie_closed2.png");
|
||||
|
||||
// Musik-Status laden (Last-State)
|
||||
musicPlaying = py.call_sync("fortunecookie.get_music_enabled", []);
|
||||
console.log("DEBUG QML: musicPlaying geladen: " + musicPlaying);
|
||||
|
||||
// MediaPlayer Zustand synchronisieren
|
||||
if (musicPlaying) {
|
||||
mediaPlayer.play();
|
||||
}
|
||||
|
||||
// UI erst nach Initialisierung anzeigen
|
||||
appInitialized = true;
|
||||
|
||||
} catch (e) {
|
||||
console.log("ERROR QML: Initialisierung fehlgeschlagen: " + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Page {
|
||||
id: mainPage
|
||||
StackLayout {
|
||||
id: mainStack
|
||||
anchors.fill: parent
|
||||
currentIndex: 0
|
||||
|
||||
header: PageHeader {
|
||||
title: "Fortune Cookie"
|
||||
}
|
||||
// Medien-Player für Settings zugänglich machen
|
||||
property MediaPlayer stackMediaPlayer: root.globalMediaPlayer
|
||||
property MediaPlayer stackCrackPlayer: root.globalCrackPlayer
|
||||
|
||||
Image {
|
||||
id: cookieImage
|
||||
anchors.centerIn: parent
|
||||
// Geöffneter Keks ist größer als geschlossener
|
||||
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")
|
||||
fillMode: Image.PreserveAspectFit
|
||||
// ================================================================
|
||||
// SEITE 0: HAUPTSPIELBILDSCHIRM
|
||||
// ================================================================
|
||||
Page {
|
||||
id: mainPage
|
||||
objectName: "mainPage"
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
property real startY: 0
|
||||
header: PageHeader {
|
||||
title: "Fortune Cookie"
|
||||
|
||||
onPressed: startY = mouseY
|
||||
|
||||
onReleased: {
|
||||
if (mouseY < startY - units.gu(2)) {
|
||||
py.call("fortunecookie.open_fortune", [], function() {
|
||||
crackMediaPlayer.play();
|
||||
fortuneOpened = true;
|
||||
currentFortune = py.call_sync("fortunecookie.get_current_fortune", []);
|
||||
currentFortuneLabel.text = currentFortune;
|
||||
currentFortuneLabel.visible = true;
|
||||
cookieImage.source = Qt.resolvedUrl("../assets/cookie_open2.png");
|
||||
});
|
||||
// Einstellungen-Button im Header
|
||||
actions: [
|
||||
Action {
|
||||
iconName: "settings"
|
||||
text: "Einstellungen"
|
||||
onTriggered: {
|
||||
mainStack.currentIndex = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
|
||||
onClicked: {
|
||||
if (!fortuneOpened) {
|
||||
py.call("fortunecookie.open_fortune", [], function() {
|
||||
crackMediaPlayer.play();
|
||||
fortuneOpened = true;
|
||||
currentFortune = py.call_sync("fortunecookie.get_current_fortune", []);
|
||||
currentFortuneLabel.text = currentFortune;
|
||||
currentFortuneLabel.visible = true;
|
||||
cookieImage.source = Qt.resolvedUrl("../assets/cookie_open2.png");
|
||||
});
|
||||
} else {
|
||||
fortuneOpened = false;
|
||||
currentFortuneLabel.text = "";
|
||||
currentFortuneLabel.visible = false;
|
||||
cookieImage.source = Qt.resolvedUrl("../assets/cookie_closed2.png");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
id: currentFortuneLabel
|
||||
anchors {
|
||||
top: cookieImage.bottom
|
||||
topMargin: units.gu(2)
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
leftMargin: units.gu(2)
|
||||
rightMargin: units.gu(2)
|
||||
}
|
||||
text: ""
|
||||
fontSize: "large"
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
visible: false
|
||||
wrapMode: Text.WordWrap
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
|
||||
onClicked: {
|
||||
py.call("fortunecookie.get_new_fortune", [], function() {
|
||||
fortuneOpened = false;
|
||||
currentFortune = py.call_sync("fortunecookie.get_current_fortune", []);
|
||||
// ============================================================
|
||||
// INITIALISIERUNGS-TIMER
|
||||
// ============================================================
|
||||
Timer {
|
||||
id: initTimer
|
||||
interval: 1000
|
||||
running: true
|
||||
repeat: false
|
||||
onTriggered: {
|
||||
try {
|
||||
currentFortune = py.call_sync("fortunecookie.get_initial_fortune", []);
|
||||
currentFortuneLabel.text = currentFortune;
|
||||
cookieImage.source = Qt.resolvedUrl("../assets/cookie_closed2.png");
|
||||
});
|
||||
|
||||
// Musik-Status laden
|
||||
musicPlaying = py.call_sync("fortunecookie.get_music_enabled", []);
|
||||
console.log("DEBUG QML: musicPlaying geladen: " + musicPlaying);
|
||||
|
||||
// MediaPlayer Zustand synchronisieren
|
||||
if (musicPlaying) {
|
||||
mediaPlayer.play();
|
||||
}
|
||||
|
||||
// Volumes laden und setzen
|
||||
var musicVol = py.call_sync("fortunecookie.get_music_volume", []);
|
||||
var crackVol = py.call_sync("fortunecookie.get_crack_volume", []);
|
||||
mediaPlayer.volume = musicVol;
|
||||
crackMediaPlayer.volume = crackVol;
|
||||
|
||||
appInitialized = true;
|
||||
|
||||
} catch (e) {
|
||||
console.log("ERROR QML: Initialisierung fehlgeschlagen: " + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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")
|
||||
fillMode: Image.PreserveAspectFit
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
property real startY: 0
|
||||
|
||||
onPressed: startY = mouseY
|
||||
|
||||
onReleased: {
|
||||
if (mouseY < startY - units.gu(2)) {
|
||||
py.call("fortunecookie.open_fortune", [], function() {
|
||||
crackMediaPlayer.play();
|
||||
fortuneOpened = true;
|
||||
currentFortune = py.call_sync("fortunecookie.get_current_fortune", []);
|
||||
currentFortuneLabel.text = currentFortune;
|
||||
currentFortuneLabel.visible = true;
|
||||
cookieImage.source = Qt.resolvedUrl("../assets/cookie_open2.png");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
|
||||
onClicked: {
|
||||
if (!fortuneOpened) {
|
||||
py.call("fortunecookie.open_fortune", [], function() {
|
||||
crackMediaPlayer.play();
|
||||
fortuneOpened = true;
|
||||
currentFortune = py.call_sync("fortunecookie.get_current_fortune", []);
|
||||
currentFortuneLabel.text = currentFortune;
|
||||
currentFortuneLabel.visible = true;
|
||||
cookieImage.source = Qt.resolvedUrl("../assets/cookie_open2.png");
|
||||
});
|
||||
} else {
|
||||
fortuneOpened = false;
|
||||
currentFortuneLabel.text = "";
|
||||
currentFortuneLabel.visible = false;
|
||||
cookieImage.source = Qt.resolvedUrl("../assets/cookie_closed2.png");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
id: currentFortuneLabel
|
||||
anchors {
|
||||
top: cookieImage.bottom
|
||||
topMargin: units.gu(2)
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
leftMargin: units.gu(2)
|
||||
rightMargin: units.gu(2)
|
||||
}
|
||||
text: ""
|
||||
fontSize: "large"
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
visible: false
|
||||
wrapMode: Text.WordWrap
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
|
||||
onClicked: {
|
||||
py.call("fortunecookie.get_new_fortune", [], function() {
|
||||
fortuneOpened = false;
|
||||
currentFortune = py.call_sync("fortunecookie.get_current_fortune", []);
|
||||
currentFortuneLabel.text = currentFortune;
|
||||
cookieImage.source = Qt.resolvedUrl("../assets/cookie_closed2.png");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
// MUSIK-BUTTON
|
||||
// ================================================================
|
||||
Label {
|
||||
id: musicButton
|
||||
anchors {
|
||||
right: parent.right
|
||||
bottom: parent.bottom
|
||||
margins: units.gu(2)
|
||||
}
|
||||
width: units.gu(10)
|
||||
height: units.gu(10)
|
||||
text: musicPlaying ? "\uD83D\uDD0A" : "\uD83D\uDD07"
|
||||
fontSize: "xx-large"
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
color: theme.palette.normalText
|
||||
visible: appInitialized
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
|
||||
onClicked: {
|
||||
console.log("DEBUG QML: Music button clicked, current musicPlaying: " + musicPlaying);
|
||||
if (musicPlaying) {
|
||||
mediaPlayer.stop();
|
||||
} else {
|
||||
mediaPlayer.play();
|
||||
}
|
||||
musicPlaying = !musicPlaying;
|
||||
console.log("DEBUG QML: Setting music enabled to: " + musicPlaying);
|
||||
py.call("fortunecookie.set_music_enabled", [musicPlaying]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
// MUSIK-BUTTON
|
||||
// SEITE 1: EINSTELLUNGEN
|
||||
// ================================================================
|
||||
// FIX: Label DIREKT verwenden (nicht in Item nesten!) - sonst "Element is not creatable"
|
||||
// Icon-Größe: xx-large für bessere Sichtbarkeit
|
||||
// Hintergrund: transparent (wie Page-Hintergrund)
|
||||
// Erst nach Initialisierung anzeigen, um Flackern zu vermeiden
|
||||
Label {
|
||||
id: musicButton
|
||||
anchors {
|
||||
right: parent.right
|
||||
bottom: parent.bottom
|
||||
margins: units.gu(2)
|
||||
}
|
||||
width: units.gu(10)
|
||||
height: units.gu(10)
|
||||
text: musicPlaying ? "\uD83D\uDD0A" : "\uD83D\uDD07" // 🎵 oder 🔇
|
||||
fontSize: "xx-large" // Großes Icon für gute Sichtbarkeit
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
color: theme.palette.normalText
|
||||
// FIX: Erst nach Initialisierung anzeigen
|
||||
visible: appInitialized
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
|
||||
onClicked: {
|
||||
console.log("DEBUG QML: Music button clicked, current musicPlaying: " + musicPlaying);
|
||||
if (musicPlaying) {
|
||||
mediaPlayer.stop();
|
||||
} else {
|
||||
mediaPlayer.play();
|
||||
}
|
||||
musicPlaying = !musicPlaying;
|
||||
console.log("DEBUG QML: Setting music enabled to: " + musicPlaying);
|
||||
py.call("fortunecookie.set_music_enabled", [musicPlaying]);
|
||||
}
|
||||
}
|
||||
Settings {
|
||||
id: settingsPage
|
||||
// Zugriff auf Medien-Player ueber parent
|
||||
property MediaPlayer settingsMediaPlayer: mainStack.stackMediaPlayer
|
||||
property MediaPlayer settingsCrackPlayer: mainStack.stackCrackPlayer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user