fix: Last-State Bug, Musik-Button und Cookie-Größe
- Label direkt verwendet (nicht in Item genestet) - Icon-Größe auf xx-large erhöht - Musik-Button erst nach Initialisierung sichtbar - Geöffneter Keks größer (36x28 vs 32x24 GU) - Last-State Funktionen bereinigt Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
+57
-33
@@ -12,10 +12,13 @@ MainView {
|
|||||||
height: units.gu(75)
|
height: units.gu(75)
|
||||||
theme.name: "Lomiri.Components.Themes.SuruDark"
|
theme.name: "Lomiri.Components.Themes.SuruDark"
|
||||||
|
|
||||||
|
// ====================================================================
|
||||||
|
// PROPERTIES (am Anfang definieren!)
|
||||||
|
// ====================================================================
|
||||||
property bool fortuneOpened: false
|
property bool fortuneOpened: false
|
||||||
property string currentFortune: ""
|
property string currentFortune: ""
|
||||||
property bool musicPlaying: false
|
property bool musicPlaying: false
|
||||||
property bool musicButtonVisible: false
|
property bool appInitialized: false
|
||||||
|
|
||||||
Python {
|
Python {
|
||||||
id: py
|
id: py
|
||||||
@@ -40,6 +43,40 @@ MainView {
|
|||||||
volume: 1.0
|
volume: 1.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ====================================================================
|
||||||
|
// INITIALISIERUNGS-TIMER
|
||||||
|
// ====================================================================
|
||||||
|
// 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 {
|
Page {
|
||||||
id: mainPage
|
id: mainPage
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
@@ -48,30 +85,10 @@ MainView {
|
|||||||
title: "Fortune Cookie"
|
title: "Fortune Cookie"
|
||||||
}
|
}
|
||||||
|
|
||||||
Timer {
|
|
||||||
id: initTimer
|
|
||||||
interval: 1000 // Warte 1 Sekunde auf Python-Ladung
|
|
||||||
running: true
|
|
||||||
repeat: false
|
|
||||||
onTriggered: {
|
|
||||||
try {
|
|
||||||
currentFortuneLabel.text = py.call_sync("fortunecookie.get_initial_fortune", []);
|
|
||||||
cookieImage.source = Qt.resolvedUrl("../assets/cookie_closed2.png");
|
|
||||||
musicPlaying = py.call_sync("fortunecookie.get_music_enabled", []);
|
|
||||||
console.log("DEBUG QML: musicPlaying loaded from Python: " + musicPlaying);
|
|
||||||
if (musicPlaying) {
|
|
||||||
mediaPlayer.play();
|
|
||||||
}
|
|
||||||
musicButtonVisible = true;
|
|
||||||
} catch (e) {
|
|
||||||
console.log("ERROR QML: Failed to initialize: " + e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Image {
|
Image {
|
||||||
id: cookieImage
|
id: cookieImage
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
|
// Geöffneter Keks ist größer als geschlossener
|
||||||
width: fortuneOpened ? units.gu(36) : units.gu(32)
|
width: fortuneOpened ? units.gu(36) : units.gu(32)
|
||||||
height: fortuneOpened ? units.gu(28) : units.gu(24)
|
height: fortuneOpened ? units.gu(28) : units.gu(24)
|
||||||
source: fortuneOpened ? Qt.resolvedUrl("../assets/cookie_open2.png") : Qt.resolvedUrl("../assets/cookie_closed2.png")
|
source: fortuneOpened ? Qt.resolvedUrl("../assets/cookie_open2.png") : Qt.resolvedUrl("../assets/cookie_closed2.png")
|
||||||
@@ -90,6 +107,7 @@ MainView {
|
|||||||
fortuneOpened = true;
|
fortuneOpened = true;
|
||||||
currentFortune = py.call_sync("fortunecookie.get_current_fortune", []);
|
currentFortune = py.call_sync("fortunecookie.get_current_fortune", []);
|
||||||
currentFortuneLabel.text = currentFortune;
|
currentFortuneLabel.text = currentFortune;
|
||||||
|
currentFortuneLabel.visible = true;
|
||||||
cookieImage.source = Qt.resolvedUrl("../assets/cookie_open2.png");
|
cookieImage.source = Qt.resolvedUrl("../assets/cookie_open2.png");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -133,7 +151,7 @@ MainView {
|
|||||||
text: ""
|
text: ""
|
||||||
fontSize: "large"
|
fontSize: "large"
|
||||||
horizontalAlignment: Text.AlignHCenter
|
horizontalAlignment: Text.AlignHCenter
|
||||||
visible: fortuneOpened
|
visible: false
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
@@ -150,8 +168,15 @@ MainView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
// ================================================================
|
||||||
id: musicButtonContainer
|
// MUSIK-BUTTON
|
||||||
|
// ================================================================
|
||||||
|
// 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 {
|
anchors {
|
||||||
right: parent.right
|
right: parent.right
|
||||||
bottom: parent.bottom
|
bottom: parent.bottom
|
||||||
@@ -159,13 +184,13 @@ MainView {
|
|||||||
}
|
}
|
||||||
width: units.gu(10)
|
width: units.gu(10)
|
||||||
height: units.gu(10)
|
height: units.gu(10)
|
||||||
visible: musicButtonVisible
|
text: musicPlaying ? "\uD83D\uDD0A" : "\uD83D\uDD07" // 🎵 oder 🔇
|
||||||
|
fontSize: "xx-large" // Großes Icon für gute Sichtbarkeit
|
||||||
Label {
|
horizontalAlignment: Text.AlignHCenter
|
||||||
id: musicButton
|
verticalAlignment: Text.AlignVCenter
|
||||||
text: musicPlaying ? "\uD83D\uDD0A" : "\uD83D\uDD07"
|
color: theme.palette.normalText
|
||||||
fontSize: "x-large"
|
// FIX: Erst nach Initialisierung anzeigen
|
||||||
anchors.centerIn: parent
|
visible: appInitialized
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
@@ -185,5 +210,4 @@ MainView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+62
-50
@@ -2,6 +2,7 @@
|
|||||||
Fortune Cookie v1.0 - Python Backend Module
|
Fortune Cookie v1.0 - Python Backend Module
|
||||||
Framework 1.7 Standard
|
Framework 1.7 Standard
|
||||||
Audio-Steuerung in QML (keine Qt-Python-Bindings benoetigt)
|
Audio-Steuerung in QML (keine Qt-Python-Bindings benoetigt)
|
||||||
|
Last-State Speicherung mit Datei-basiertem Speicher
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
@@ -17,6 +18,7 @@ APP_NAME = "fortunecookie"
|
|||||||
APP_VERSION = "1.0.0"
|
APP_VERSION = "1.0.0"
|
||||||
MAINTAINER = "darklithium <dev@darklithium.de>"
|
MAINTAINER = "darklithium <dev@darklithium.de>"
|
||||||
|
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# PLATTFORM-ERKENNUNG (Framework 1.7 Standard)
|
# PLATTFORM-ERKENNUNG (Framework 1.7 Standard)
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
@@ -38,9 +40,6 @@ _current_fortune = ""
|
|||||||
_fortunes = []
|
_fortunes = []
|
||||||
_initialized = False
|
_initialized = False
|
||||||
|
|
||||||
# Musik-Status (wird dynamisch von Datei geladen)
|
|
||||||
# _music_enabled wird nicht als globale Variable gespeichert, sondern immer frisch geladen
|
|
||||||
|
|
||||||
|
|
||||||
def _init():
|
def _init():
|
||||||
"""Initialisiert das Modul (wird beim ersten Aufruf ausgefuehrt)."""
|
"""Initialisiert das Modul (wird beim ersten Aufruf ausgefuehrt)."""
|
||||||
@@ -138,80 +137,93 @@ def get_new_fortune():
|
|||||||
# ============================================================================
|
# ============================================================================
|
||||||
# LAST-STATE SPEICHERUNG (Musik an/aus)
|
# LAST-STATE SPEICHERUNG (Musik an/aus)
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
|
#
|
||||||
|
# Verwende diese Funktionen, um App-Zustände zwischen App-Starts zu speichern.
|
||||||
|
# WICHTIG:
|
||||||
|
# - In Click-Apps: ~/.cache/<appname>/ ist beschreibbar
|
||||||
|
# - Datei-Inhalt: Einfach "true" oder "false" als String speichern
|
||||||
|
# - Immer FRISCH aus Datei laden (kein Caching!)
|
||||||
|
|
||||||
|
# Cache-Verzeichnis für Konfigurationen
|
||||||
def _get_config_dir():
|
def _get_config_dir():
|
||||||
"""Gibt das Konfigurationsverzeichnis der App zurueck.
|
"""Gibt das Konfigurationsverzeichnis zurück (Click-App kompatibel)."""
|
||||||
|
|
||||||
Click-Apps auf UBPorts haben eingeschraenkte Schreibrechte.
|
|
||||||
Verwendete Pfade:
|
|
||||||
- ~/.cache/<appname>/ (funktioniert in Click-Apps)
|
|
||||||
"""
|
|
||||||
try:
|
try:
|
||||||
home = os.path.expanduser("~")
|
home = os.path.expanduser("~")
|
||||||
# Click-App-Pfad (funktioniert in der Sandbox)
|
app_name = APP_NAME + ".darklithium"
|
||||||
app_name = "fortunecookie.darklithium"
|
|
||||||
cache_dir = os.path.join(home, ".cache", app_name)
|
cache_dir = os.path.join(home, ".cache", app_name)
|
||||||
os.makedirs(cache_dir, exist_ok=True)
|
os.makedirs(cache_dir, exist_ok=True)
|
||||||
return cache_dir
|
return cache_dir
|
||||||
except Exception:
|
except Exception:
|
||||||
# Fallback
|
# Fallback für Tests
|
||||||
return os.path.join("/tmp", "fortunecookie")
|
return os.path.join("/tmp", APP_NAME + "_config")
|
||||||
|
|
||||||
|
|
||||||
def _get_music_state_file():
|
def _get_state_file(state_name):
|
||||||
"""Gibt den Pfad zur Musik-Status-Datei zurueck."""
|
"""Gibt den Pfad zu einer Zustandsdatei zurück."""
|
||||||
config_dir = _get_config_dir()
|
return os.path.join(_get_config_dir(), state_name)
|
||||||
return os.path.join(config_dir, "music_enabled")
|
|
||||||
|
|
||||||
|
|
||||||
def _load_music_state():
|
def load_state(state_name, default_value=True):
|
||||||
"""Laedt den Musik-Status aus Datei (true/false)."""
|
"""Lädt einen Zustand aus einer Datei.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
state_name (str): Name des Zustands
|
||||||
|
default_value (bool): Standardwert, wenn Datei nicht existiert
|
||||||
|
|
||||||
|
Rückgabe:
|
||||||
|
bool: Der geladene Zustand (True/False)
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
state_file = _get_music_state_file()
|
state_file = _get_state_file(state_name)
|
||||||
print(f"DEBUG: Loading music state from: {state_file}")
|
|
||||||
print(f"DEBUG: File exists: {os.path.exists(state_file)}")
|
|
||||||
if os.path.exists(state_file):
|
if os.path.exists(state_file):
|
||||||
with open(state_file, "r") as f:
|
with open(state_file, "r") as f:
|
||||||
content = f.read().strip().lower()
|
content = f.read().strip().lower()
|
||||||
print(f"DEBUG: File content: '{content}'")
|
return content == "true"
|
||||||
result = content == "true"
|
|
||||||
print(f"DEBUG: Music enabled: {result}")
|
|
||||||
return result
|
|
||||||
else:
|
|
||||||
print("DEBUG: Music state file does not exist, using default: True")
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"WARN: Musik-Status nicht geladen: {e}")
|
print(f"WARN: Zustand nicht geladen ({state_name}): {e}")
|
||||||
import traceback
|
return default_value
|
||||||
traceback.print_exc()
|
|
||||||
# Default: Musik an
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def _save_music_state(enabled):
|
def save_state(state_name, value):
|
||||||
"""Speichert den Musik-Status in Datei (true/false)."""
|
"""Speichert einen Zustand in einer Datei.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
state_name (str): Name des Zustands
|
||||||
|
value (bool): Der zu speichernde Zustand (True/False)
|
||||||
|
|
||||||
|
Rückgabe:
|
||||||
|
bool: True bei Erfolg
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
config_dir = _get_config_dir()
|
config_dir = _get_config_dir()
|
||||||
os.makedirs(config_dir, exist_ok=True)
|
os.makedirs(config_dir, exist_ok=True)
|
||||||
state_file = _get_music_state_file()
|
state_file = _get_state_file(state_name)
|
||||||
print(f"DEBUG: Saving music state {enabled} to: {state_file}")
|
|
||||||
with open(state_file, "w") as f:
|
with open(state_file, "w") as f:
|
||||||
f.write("true" if enabled else "false")
|
f.write("true" if value else "false")
|
||||||
print(f"DEBUG: Successfully saved music state")
|
|
||||||
except Exception as e:
|
|
||||||
print(f"WARN: Musik-Status nicht gespeichert: {e}")
|
|
||||||
import traceback
|
|
||||||
traceback.print_exc()
|
|
||||||
|
|
||||||
|
|
||||||
def set_music_enabled(enabled):
|
|
||||||
"""Aktiviert/Deaktiviert die Musik und speichert den Status."""
|
|
||||||
_save_music_state(enabled)
|
|
||||||
return True
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
print(f"WARN: Zustand nicht gespeichert ({state_name}): {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def get_music_enabled():
|
def get_music_enabled():
|
||||||
"""Gibt den Musik-Status zurueck (frisch von Datei geladen)."""
|
"""Gibt zurück, ob Musik aktiviert ist (Last-State).
|
||||||
return _load_music_state()
|
|
||||||
|
Lädt den Zustand FRISCH aus der Datei bei jedem Aufruf.
|
||||||
|
"""
|
||||||
|
return load_state("music_enabled", default_value=True)
|
||||||
|
|
||||||
|
|
||||||
|
def set_music_enabled(enabled):
|
||||||
|
"""Setzt den Musik-Status und speichert ihn persistent.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
enabled (bool): True = Musik an, False = Musik aus
|
||||||
|
|
||||||
|
Rückgabe:
|
||||||
|
bool: True bei Erfolg
|
||||||
|
"""
|
||||||
|
return save_state("music_enabled", enabled)
|
||||||
|
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
|
|||||||
Reference in New Issue
Block a user