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:
darklithium
2026-06-02 21:26:41 +02:00
parent da719d7670
commit c4e7d4bd55
7 changed files with 1019 additions and 235 deletions
+143
View File
@@ -0,0 +1,143 @@
# 📁 FortuneCookie - Asset Anforderungen
**Version:** 1.0.1
**Datum:** 02.06.2026
**Zweck:** Spezifikationen für Grafik-Assets (Hintergründe, Logos, Icons)
---
## 🎨 Allgemeine Anforderungen
### Dateiformate
| Asset-Typ | Empfohlen | Alternative | Grund |
|-----------|-----------|-------------|-------|
| Hintergründe | `.png` | `.jpg` | Transparenz möglich, gute Qualität |
| Logos | `.png` | `.svg` | Transparenz, scharfe Kanten |
| Icons | `.png` | - | Konsistenz mit bestehenden Assets |
### Dateinamen-Konventionen
- **Nur Kleinbuchstaben** (z. B. `background_70s.png`, nicht `Background_70s.PNG`)
- **Bindestriche statt Leerzeichen** (z. B. `seventies-style.png`, nicht `seventies style.png`)
- **Keine Umlaute/Sonderzeichen** (z. B. `esoteric.png`, nicht `esoterisch.png`)
- **Keine Versionen in Dateinamen** (z. B. `logo.png`, nicht `logo_v2_final.png`)
---
## 📏 Größen & Auflösungen
### Hintergründe
- **Abmessungen:** **1080 × 1920 Pixel** (Full HD, 16:9)
- **QML-Einheit:** 45 GU (Breite) × 75 GU (Höhe) = 1080×1920 px
- **Dateigröße:** **Max. 500 KB pro Bild**
- **Farbraum:** RGB
- **Transparenz:** Optional (PNG unterstützt Alpha-Kanal)
**Benötigte Varianten:**
```
assets/backgrounds/
├── 70s.png # 70er-Jahre Stil (Disco, Retro)
├── esoteric.png # Esoterisch (Mystik, Tarot, spirituell)
└── heavenly.png # Himmelisch (Wolken, Engel, Licht)
```
### Logos
- **Haupt-Logo (Startseite):** **240 × 240 Pixel** (ca. 30 GU × 30 GU)
- **Button-Icon (Musik):** **80 × 80 Pixel** (ca. 10 GU × 10 GU)
- **Dateigröße:** Max. 200 KB pro Logo
- **Transparenz:** **Pflicht** (PNG mit Alpha-Kanal)
- **Farbraum:** RGB
**Benötigte Varianten:**
```
assets/logos/
├── default.png # Standard Logo (Glückskeks)
├── 70s.png # 70er-Jahre Stil (passend zu Hintergrund)
├── esoteric.png # Esoterisch (passend zu Hintergrund)
├── heavenly.png # Himmelisch (passend zu Hintergrund)
└── unfortune.png # Gothic/Dark (Totenköpfe, Lilafarben, Blitze)
```
### Icons
- **Musik-Button:** Emoji (🎵/🔇) oder PNG (80×80 px)
- **Dateigröße:** Max. 50 KB
- **Transparenz:** Pflicht
---
## 📂 Verzeichnis-Struktur
```
fortunecookie-neu/
└── testing/
└── assets/
├── ASSET_REQUIREMENTS.md # ← Diese Datei
├── backgrounds/ # Hintergrundbilder (Full HD)
│ ├── 70s.png
│ ├── esoteric.png
│ └── heavenly.png
├── logos/ # Logos (240×240 px, transparent)
│ ├── default.png
│ ├── 70s.png
│ ├── esoteric.png
│ ├── heavenly.png
│ └── unfortune.png
└── sounds/ # Bestehend
├── chinese_music.mp3
└── cookie_crack.mp3
```
---
## ⚠️ WICHTIGE HINWEISE für Ubuntu Touch
### 1. QML-Kompatibilität
- **SVG-Unterstützung:** Begrenzt in Lomiri/QML - **PNG bevorzugen**
- **Transparenz:** Funktioniert mit PNG (Alpha-Kanal)
- **Skalierung:** Bilder werden automatisch skaliert, aber native Auflösung empfohlen
### 2. QML-Integration
Hintergründe einbinden:
```qml
Image {
id: background
anchors.fill: parent
source: Qt.resolvedUrl("../assets/backgrounds/70s.png")
fillMode: Image.PreserveAspectCrop
}
```
Logos einbinden:
```qml
Image {
id: logo
width: units.gu(30)
height: units.gu(30)
source: Qt.resolvedUrl("../assets/logos/70s.png")
fillMode: Image.PreserveAspectFit
}
```
### 3. Performance
- **Maximale Dateigröße:** 1 MB pro Asset (Click-App Limit)
- **Optimierung:** Bilder vor dem Einbinden mit `optipng` oder `pngquant` komprimieren
- **Anzahl:** Max. 20-30 Assets pro App (für schnelles Laden)
---
## 🎯 Nächste Schritte (Phase 1)
1. **Erstelle die Bilder** according to den Spezifikationen
2. **Speichere sie** im richtigen Verzeichnis (`assets/backgrounds/` und `assets/logos/`)
3. **Benenne sie** nach der Konvention
4. **Informiere mich** - ich baue die Auswahl-Funktionalität in die Einstellungen ein
---
## 📞 Support
Fragen zu den Anforderungen?
→ einfach fragen oder in den entsprechenden Kanälen nachfragen.
+280
View File
@@ -0,0 +1,280 @@
{
"de": [
"Heute ist ein guter Tag für neue Abenteuer!",
"Achte auf kleine Zeichen sie führen dich weiter.",
"Ein Lächeln bringt Glück in dein Leben.",
"Die größten Chancen kommen oft unerwartet.",
"Geduld ist der Schlüssel zu vielen Türen.",
"Ein offenes Herz sieht mehr als tausend Augen.",
"Vertraue dem Prozess, auch wenn du den Ausgang nicht kennst.",
"Alles fließt auch deine Situation wird sich ändern.",
"Gib nicht auf, selbst wenn der Weg steinig erscheint.",
"Ein wahrer Freund ist ein Geschenk des Himmels.",
"Die beste Zeit, einen Baum zu pflanzen, war vor 20 Jahren. Die zweitbeste Zeit ist jetzt.",
"Glück ist kein Zufall, sondern die Folge von harter Arbeit und positiver Einstellung.",
"Wer andere glücklich macht, wird selbst glücklich sein.",
"Manchmal muss man einen Schritt zurückgehen, um zwei Schritte vorwärts zu kommen.",
"Das Leben ist wie ein Fahrrad. Um die Balance zu halten, muss man in Bewegung bleiben.",
"Ein kluger Mensch lernt aus der Erfahrung anderer.",
"Die größten Entdeckungen kommen oft aus Neugier.",
"Wer rastet, der rostet.",
"Ein gutes Buch und eine Tasse Tee sind die besten Begleiter.",
"Die Sonne scheint auch nach dem dunkelsten Tag wieder.",
"Glück ist die Fähigkeit, das Gute im Schlechten zu sehen.",
"Ein Lächeln kostet nichts und bringt viel zurück.",
"Wer nach vorne schaut, sieht die Zukunft.",
"Manchmal ist der Weg das Ziel.",
"Ein freundliches Wort kann einen schlechten Tag retten.",
"Die Natur ist die beste Quelle der Inspiration.",
"Der Weg ist das Ziel genieße die Reise, nicht nur das Ziel.",
"Jeder Tag ist eine neue Chance, alles zu ändern.",
"Das Glück liegt in den kleinen Dingen des Lebens.",
"Was du aussäst, wirst du ernten.",
"Lache oft, liebe viel, vergiß nie wie gut das Leben sein kann.",
"Ein Tag ohne Lächeln ist ein verlorener Tag.",
"Die Zukunft gehört denen, die an die Schönheit ihrer Träume glauben.",
"Tu heute etwas, wofür dich dein zukünftiges Ich bedanken wird.",
"Der beste Weg, die Zukunft vorauszusagen, ist sie zu gestalten.",
"Träume sind nicht für die, die schlafen, sondern für die, die nicht aufgeben.",
"Jeder Moment ist eine neue Möglichkeit.",
"Das Geheimnis des Glücks liegt nicht im Besitz, sondern in der Freiheit von Besessenheit.",
"Lebe jeden Tag so, als wäre es dein letzter eines Tages hast du recht.",
"Die größte Entdeckung einer Generation ist, dass ein Mensch sein Leben ändern kann, indem er seine Einstellung ändert.",
"Glück ist nicht etwas, das man findet, es ist etwas, das man schafft.",
"Die beste Rache ist ein gut geführtes Leben.",
"Gib jedem Tag die Chance, der beste Tag deines Lebens zu sein.",
"Man sieht nur mit dem Herzen gut. Das Wesentliche ist für die Augen unsichtbar.",
"Was immer du tun kannst oder träumst zu tun, fang damit an. Mut hat Genie, Kraft und Magie in sich.",
"Die einfachsten Dinge bringen oft das größte Glück.",
"Ein Leben ohne Risiko ist ein Leben ohne Chancen.",
"Alles, was du brauchst, ist bereits in dir.",
"Der einzige Weg, Großes zu erreichen, ist, es als eine Reihe kleiner Schritte zu betrachten.",
"Was du heute tust, wird deine morgen bewirken.",
"Ein positiver Geist bringt positive Dinge ins Leben.",
"Die beste Zeit, glücklich zu sein, ist jetzt. Der beste Ort, glücklich zu sein, ist hier. Der beste Weg, glücklich zu sein, ist mit anderen.",
"Lebe nicht in der Vergangenheit, träume nicht von der Zukunft, konzentriere dich auf den gegenwärtigen Moment.",
"Glück ist kein Zufall. Es ist das Ergebnis deiner täglichen Gewohnheiten.",
"Die Welt ist voll von wundervollen Dingen, die wir nicht sehen können.",
"Sei du selbst die Veränderung, die du in der Welt sehen möchtest.",
"Jeder Tag bietet eine neue Seite in deinem Lebensbuch.",
"Das Geheimnis des Erfolgs ist, den ersten Schritt zu tun.",
"Lächle, auch wenn dein Herz schmerzt. Lächle, auch wenn es Tränen gibt.",
"Die meisten unserer Ängste sind größtenteils imaginär.",
"Vertraue auf die Zeit. Sie ist ein wunderbarer Erzähler.",
"Ein Buch und eine Tasse Kaffee können die Welt verändern.",
"Die beste Investition, die du machen kannst, ist in dich selbst.",
"Alles fließt, nichts bleibt. Es gibt nichts Dauerhaftes außer der Veränderung.",
"Die größere Gefahr für die meisten von uns liegt nicht darin, dass unser Ziel zu hoch ist und wir es verfehlen, sondern darin, dass es zu niedrig ist und wir es erreichen.",
"Der einzige Ort, an dem Erfolg vor Arbeit kommt, ist im Wörterbuch.",
"Lebe so, als würdest du morgen sterben. Lerne so, als würdest du ewig leben.",
"Was immer du tust, tue es mit ganzem Herzen.",
"Ein Tag ohne Lachen ist ein verlorener Tag.",
"Das Leben ist wie eine Kamera einfach lächeln und einen guten Tag haben.",
"Die besten Dinge im Leben sind nicht die, die man für Geld kaufen kann.",
"Denke daran, dass das Glück ein Weg, nicht ein Ziel.",
"Jeder Tag ist eine neue Gelegenheit, besser zu sein als gestern.",
"Die Sonne wird wieder scheinen, auch wenn es heute regnet.",
"Ein kluger Mann macht nicht alle Fehler selbst. Er gibt auch anderen eine Chance.",
"Der frühe Vogel fängt den Wurm, aber der zweite Mäuse bekommt den Käse.",
"Einfachheit ist die höchste Form der Raffinesse.",
"In der Mitte jeder Schwierigkeit liegt eine Gelegenheit.",
"Deine Einstellung, nicht deine Fähigkeiten, wird deine Höhe bestimmen.",
"Glück ist wie ein Schmetterling. Wenn du es jagst, fliegt es davon. Wenn du dich hinsetzt, kommt es und setzt sich auf deine Schulter.",
"Die beste Art, sich selbst zu finden, ist, sich im Dienst an anderen zu verlieren.",
"Erfolg ist nicht der Schlüssel zum Glück. Glück ist der Schlüssel zum Erfolg.",
"Der beste Rat, den ich je bekommen habe: Sei du selbst.",
"Das Leben ist kurz. Lächele, während du noch Zähne hast.",
"Ein Tag ohne Musik ist ein verlorener Tag.",
"Die größte Freude im Leben ist zu lieben und geliebt zu werden.",
"Lebe jeden Tag so, als wäre es dein letzter, eines Tages wirst du Recht haben.",
"Die beste Zeit, um glücklich zu sein, ist jetzt.",
"Ein wahres Zeichen von Reife ist, wenn jemand dich verletzt und du versuchst, sie zu verstehen, anstatt sie zu verletzen.",
"Der beste Weg, mit der Zukunft fertig zu werden, ist, sie Schritt für Schritt zu bewältigen.",
"Glück ist eine Richtung, kein Ort.",
"Die Schönheit des Lebens liegt in seinen Unvollkommenheiten.",
"Ein Freund ist jemand, der die Melodie deines Herzens kennt und sie mitsingt, wenn du sie vergisst.",
"Das Geheimnis, im Leben voranzukommen, ist, loszulassen und loszulassen.",
"Die besten Dinge im Leben kommen unerwartet.",
"Lächle, es ist ansteckend.",
"Die beste Medizin gegen Stress ist ein tiefer Atem und ein Lächeln.",
"Glück ist die Summe kleiner Glücksmomente.",
"Der beste Weg, die Zukunft vorherzusagen, ist, sie zu gestalten.",
"Ein Tag mit einem Lächeln ist ein guter Tag.",
"Die einfachsten Dinge sind oft die schönsten.",
"Ein Buch kann die Welt verändern, eine Idee kann die Geschichte schreiben.",
"Die beste Investition ist die in den eigenen Geist.",
"Alles, was du in deinem Leben siehst, ist das Ergebnis dessen, was du in deinem Geist siehst.",
"Die größte Kraft, die ein Mensch besitzen kann, ist die Macht, sein eigenes Denken zu verändern.",
"Der beste Weg, ein Ziel zu erreichen, ist, nie aufzugeben.",
"Lebe so, dass du am Ende des Tages sagen kannst: Es war ein guter Tag.",
"Die besten Erinnerungen sind die, die wir mit anderen teilen.",
"Ein wahrer Freund ist jemand, der dich versteht, auch wenn er nicht mit dir übereinstimmt.",
"Der beste Weg, das Leben zu genießen, ist, im Moment zu leben.",
"Glück ist kein Zustand, sondern eine Entscheidung.",
"Die größten Geschenke des Lebens sind die einfachen Freuden.",
"Ein Lächeln ist die kürzeste Distanz zwischen zwei Menschen.",
"Die beste Art zu leben ist, im Hier und Jetzt zu leben.",
"Jeder Tag ist eine neue Gelegenheit, das Leben in vollen Zügen zu genießen.",
"Der beste Freund ist jemand, der dich so liebt, wie du bist.",
"Ein Leben in Harmonie mit der Natur bringt wahre Freude.",
"Die beste Medizin für eine schlechte Laune ist ein gutes Gespräch.",
"Glück ist wie ein Garten: Es wächst, wenn es gepflegt wird.",
"Die größten Wunder des Lebens sind die kleinen Dinge, die wir oft übersehen.",
"Ein wahres Lächeln kommt von Herzen und kann jeden Tag erhellen.",
"Die beste Art, die Zukunft zu sehen, ist, mit einem Lächeln in den Spiegel zu schauen.",
"Lebe jeden Tag mit der Gewissheit, dass du das Beste daraus machst.",
"Die größte Freude liegt in den einfachen Dingen, die wir oft als selbstverständlich betrachten.",
"Ein guter Tag beginnt mit einer positiven Einstellung und einem Lächeln.",
"Das Leben ist ein Geschenk verpacke es mit Liebe und Freude aus.",
"Die beste Art, Glück zu finden, ist, es mit anderen zu teilen.",
"Jeder Moment ist eine neue Gelegenheit, etwas Großartiges zu beginnen.",
"Ein wahrer Schatz im Leben ist ein Freund, der immer für dich da ist.",
"Die beste Zeit, um dankbar zu sein, ist jetzt.",
"Glück ist kein Ziel, sondern eine Lebensweise.",
"Ein Lächeln ist die universelle Sprache der Freundlichkeit.",
"Die besten Dinge im Leben sind die, die wir mit Liebe und Leidenschaft tun.",
"Lebe jeden Tag so, als wäre er ein Geschenk denn das ist er.",
"Die größte Befriedigung kommt von innen, nicht von außen.",
"Ein wahres Lächeln kann die Welt verändern, einen Menschen nach dem anderen.",
"Die beste Art, die Zukunft zu gestalten, ist, heute das Beste zu geben.",
"Glück ist wie ein Baum: Es wächst, wenn es mit Liebe und Sorgfalt gepflegt wird.",
"Jeder Tag ist eine neue Seite in deinem Lebensbuch schreibe eine schöne Geschichte."
],
"en": [
"Today is a good day for new adventures!",
"Pay attention to small signs they guide you.",
"A smile brings happiness to your life.",
"The greatest opportunities often come unexpectedly.",
"Patience is the key to many doors.",
"An open heart sees more than a thousand eyes.",
"Trust the process, even if you don't know the outcome.",
"Everything flows your situation will change too.",
"Don't give up, even if the path seems rocky.",
"A true friend is a gift from heaven.",
"The best time to plant a tree was 20 years ago. The second best time is now.",
"Happiness is not a coincidence, but the result of hard work and positive attitude.",
"Who makes others happy will be happy themselves.",
"Sometimes you need to take a step back to move two steps forward.",
"Life is like a bicycle. To keep your balance, you must keep moving.",
"A wise person learns from the experience of others.",
"The greatest discoveries often come from curiosity.",
"Who rests, rusts.",
"A good book and a cup of tea are the best companions.",
"The sun also shines after the darkest day.",
"Happiness is the ability to see the good in the bad.",
"A smile costs nothing and brings back a lot.",
"The journey is the destination enjoy the ride, not just the arrival.",
"Every day is a new opportunity to change everything.",
"Happiness lies in the little things of life.",
"You reap what you sow.",
"Laugh often, love much, never forget how good life can be.",
"A day without a smile is a lost day.",
"The future belongs to those who believe in the beauty of their dreams.",
"Do something today that your future self will thank you for.",
"The best way to predict the future is to create it.",
"Dreams are not for those who sleep, but for those who don't give up.",
"Every moment is a new opportunity.",
"The secret of happiness is not in possession, but in freedom from possession.",
"Live each day as if it were your last one day you'll be right.",
"The greatest discovery of a generation is that a person can change their life by changing their attitude.",
"Happiness is not something you find, it is something you create.",
"The best revenge is a life well lived.",
"Give every day a chance to be the best day of your life.",
"One sees clearly only with the heart. What is essential is invisible to the eye.",
"Whatever you can do or dream you can, begin it. Boldness has genius, power and magic in it.",
"The simplest things often bring the greatest happiness.",
"A life without risk is a life without opportunity.",
"Everything you need is already within you.",
"The only way to achieve great things is to view them as a series of small steps.",
"What you do today determines your tomorrow.",
"A positive mind brings positive things into life.",
"The best time to be happy is now. The best place to be happy is here. The best way to be happy is with others.",
"Don't live in the past, don't dream of the future, concentrate on the present moment.",
"Happiness is not a coincidence. It is the result of your daily habits.",
"The world is full of wonderful things we cannot see.",
"Be the change that you wish to see in the world.",
"Every day offers a new page in your life's book.",
"The secret of success is to take the first step.",
"Smile, even if your heart aches. Smile, even if there are tears.",
"Most of our fears are largely imaginary.",
"Trust in time. It is a wonderful storyteller.",
"A book and a cup of coffee can change the world.",
"The best investment you can make is in yourself.",
"Everything flows, nothing stands still. There is nothing permanent except change.",
"The greatest danger for most of us is not that our aim is too high and we miss it, but that it is too low and we reach it.",
"The only place where success comes before work is in the dictionary.",
"Live as if you were to die tomorrow. Learn as if you were to live forever.",
"Whatever you do, do it with all your heart.",
"A day without laughter is a lost day.",
"Life is like a camera just smile and have a good day.",
"The best things in life are not the ones you can buy with money.",
"Remember that happiness is a way, not a destination.",
"Every day is a new opportunity to be better than yesterday.",
"The sun will shine again, even if it's raining today.",
"A wise man doesn't make all the mistakes himself. He gives others a chance too.",
"The early bird catches the worm, but the second mouse gets the cheese.",
"Simplicity is the ultimate sophistication.",
"In the middle of every difficulty lies opportunity.",
"Your attitude, not your aptitude, will determine your altitude.",
"Happiness is like a butterfly. If you chase it, it will elude you. If you sit quietly, it may land on your shoulder.",
"The best way to find yourself is to lose yourself in the service of others.",
"Happiness is not the key to success. Success is the key to happiness.",
"The best advice I ever received: Be yourself.",
"Life is short. Smile while you still have teeth.",
"A day without music is a day wasted.",
"The greatest joy in life is to love and be loved.",
"Live each day as if it were your last, one day you will be right.",
"The best time to be happy is now.",
"A true sign of maturity is when someone hurts you and you try to understand them instead of hurting them back.",
"The best way to deal with the future is to take it one step at a time.",
"Happiness is a direction, not a place.",
"The beauty of life lies in its imperfections.",
"A friend is someone who knows the melody of your heart and sings it back to you when you have forgotten the words.",
"The secret of getting ahead is getting started and letting go of distractions.",
"The best things in life happen unexpectedly.",
"Smile, it's contagious.",
"The best medicine for stress is a deep breath and a smile.",
"Happiness is the sum of small happy moments.",
"The best way to predict the future is to create it with a smile.",
"A day with a smile is a good day.",
"The simplest things are often the most beautiful.",
"A book can change the world, an idea can write history.",
"The best investment is the one in your own mind.",
"Everything you see in your life is the result of what you see in your mind.",
"The greatest power a person can possess is the power to change their own thinking.",
"The best way to achieve a goal is to never give up.",
"Live so that at the end of the day you can say: It was a good day.",
"The best memories are the ones we share with others.",
"A true friend is someone who understands you even when they don't agree with you.",
"The best way to enjoy life is to live in the moment.",
"Happiness is not a condition, but a decision.",
"The greatest gifts in life are the simple joys.",
"A smile is the shortest distance between two people.",
"The best way to live is to live in the here and now.",
"Every day is a new opportunity to enjoy life to the fullest.",
"The best friend is someone who loves you for who you are.",
"A life in harmony with nature brings true joy.",
"The best medicine for a bad mood is a good conversation.",
"Happiness is like a garden: it grows when it is nurtured.",
"The greatest miracles of life are the small things we often overlook.",
"A true smile comes from the heart and can brighten any day.",
"The best way to see the future is to look in the mirror with a smile.",
"Live each day with the certainty that you are making the best of it.",
"The greatest joy lies in the simple things we often take for granted.",
"A good day starts with a positive attitude and a smile.",
"Life is a gift wrap it with love and joy.",
"The best way to find happiness is to share it with others.",
"Every moment is a new opportunity to start something great.",
"A true treasure in life is a friend who is always there for you.",
"The best time to be grateful is now.",
"Happiness is not a destination, but a way of life.",
"A smile is the universal language of kindness.",
"The best things in life are the ones we do with love and passion.",
"Live each day as if it were a gift because it is.",
"The greatest satisfaction comes from within, not from without.",
"A true smile can change the world, one person at a time.",
"The best way to shape the future is to give your best today.",
"Happiness is like a tree: it grows when nurtured with love and care.",
"Every day is a new page in your life's book write a beautiful story."
]
}
+22
View File
@@ -0,0 +1,22 @@
[
"Wenn der Hahn kräht auf dem Mist, ändert sich das Wetter oder es bleibt wie es ist.",
"Der Bauer und sein Hund, die gibt's nicht ohne Grund.",
"Wenn's im Mai regnet, wird's im Juni sonnig.",
"Die beste Zeit, einen Baum zu pflanzen, war vor 20 Jahren. Die zweitbeste Zeit ist jetzt.",
"Wer zu spät sät, der erntet nicht.",
"Ein guter Rat ist wie ein guter Regen: beide kommen von oben und beide sind nützlich.",
"Der Klügere gibt nach - und bekommt die bessere Hälfte.",
"Was der Bauer nicht kennt, das isst er nicht.",
"Wenn die Katze aus dem Haus ist, tanzen die Mäuse auf dem Tisch.",
"Wer rastet, der rostet - aber wer hetzt, der hat keine Zeit zum Rosten.",
"Ein guter Name ist besser als ein guter Sarg.",
"Derearly Vogel fängt den Wurm, aber der zweite Maus fängt den Käse.",
"Man soll den Tag nicht vor dem Abend loben.",
"Wer im Glashaus sitzt, sollte nicht mit Steinen werfen.",
"Alles hat seine Zeit: auch das Warten.",
"Ein guter Freund ist besser als ein weiter Verwandter.",
"Was du heute kannst besorgen, das verschiebe nicht auf morgen.",
"Wer zu viel will, der hat am Ende nichts.",
"Ein guter Rat kommt selten zur Unzeit.",
"Der Hunger kommt beim Essen."
]
+23
View File
@@ -0,0 +1,23 @@
[
"Das Glück ist ein wandelnder Stern, der mal hier, mal dort einkehrt, doch nie bei dir verweilt.",
"Die Hoffnung stirbt zuletzt - aber sie stirbt.",
"Alles was du liebst, wirst du eines Tages verlieren.",
"Das Leben ist ein Kreis aus Schmerz und Enttäuschung.",
"Die Welt ist grausam, aber mindestens ist sie ehrlich darin.",
"Jeder Tag ohne dich ist ein Tag zu viel.",
"Die Nacht ist dunkel und voll Terrible - aber wenigstens ist sie ehrlich.",
"Alles wird gut - sagte niemand, der die Wahrheit kannte.",
"Tränen sind der Regen, der deine Seele wachsen lässt - in den Abgrund.",
"Das Glück währt nur einen Augenblick, der Schmerz ewig.",
"Du bist nicht allein - aber du fühlst dich so.",
"Die Liebe ist ein Spiel, und du hast verloren.",
"Alles hat ein Ende, nur die Wurst hat zwei.",
"Der Weg zur Hölle ist mit guten Vorsätzen gepflastert - und du bist schon angekommen.",
"Lächeln ist die beste Medizin - aber sie heilt keine gebrochenen Herzen.",
"Jeder hat einen Platz im Universum. Deiner ist in der Ecke, wo das Licht nie hinkommt.",
"Die Zeit heilt alle Wunden - aber die Narben bleiben für immer.",
"Das Leben ist wie eine Zitrone: sauer, bitter und am Ende macht es deine Lippen nur noch trockener.",
"Hoffnung ist der Traum eines wachen Mannes - und Träume sind Lügen.",
"Du bist perfekt - perfekt falsch am falschen Ort zur falschen Zeit.",
"Alles was glänzt ist nicht Gold - meistens ist es nur der letzte Funke Hoffnung, bevor das Licht ausgeht."
]
+59 -21
View File
@@ -20,6 +20,10 @@ MainView {
property bool musicPlaying: false property bool musicPlaying: false
property bool appInitialized: false property bool appInitialized: false
// Medien-Player als globale Properties für Zugriff aus Settings
property MediaPlayer globalMediaPlayer: mediaPlayer
property MediaPlayer globalCrackPlayer: crackMediaPlayer
Python { Python {
id: py id: py
Component.onCompleted: { Component.onCompleted: {
@@ -44,10 +48,42 @@ MainView {
} }
// ==================================================================== // ====================================================================
// INITIALISIERUNGS-TIMER // STACK LAYOUT FÜR NAVIGATION
// ==================================================================== // ====================================================================
// WICHTIG: PyOtherSide braucht Zeit zum Laden! StackLayout {
// 1 Sekunde Verzögerung verhindert Race Conditions id: mainStack
anchors.fill: parent
currentIndex: 0
// Medien-Player für Settings zugänglich machen
property MediaPlayer stackMediaPlayer: root.globalMediaPlayer
property MediaPlayer stackCrackPlayer: root.globalCrackPlayer
// ================================================================
// SEITE 0: HAUPTSPIELBILDSCHIRM
// ================================================================
Page {
id: mainPage
objectName: "mainPage"
header: PageHeader {
title: "Fortune Cookie"
// Einstellungen-Button im Header
actions: [
Action {
iconName: "settings"
text: "Einstellungen"
onTriggered: {
mainStack.currentIndex = 1;
}
}
]
}
// ============================================================
// INITIALISIERUNGS-TIMER
// ============================================================
Timer { Timer {
id: initTimer id: initTimer
interval: 1000 interval: 1000
@@ -59,7 +95,7 @@ MainView {
currentFortuneLabel.text = currentFortune; currentFortuneLabel.text = currentFortune;
cookieImage.source = Qt.resolvedUrl("../assets/cookie_closed2.png"); cookieImage.source = Qt.resolvedUrl("../assets/cookie_closed2.png");
// Musik-Status laden (Last-State) // Musik-Status laden
musicPlaying = py.call_sync("fortunecookie.get_music_enabled", []); musicPlaying = py.call_sync("fortunecookie.get_music_enabled", []);
console.log("DEBUG QML: musicPlaying geladen: " + musicPlaying); console.log("DEBUG QML: musicPlaying geladen: " + musicPlaying);
@@ -68,7 +104,12 @@ MainView {
mediaPlayer.play(); mediaPlayer.play();
} }
// UI erst nach Initialisierung anzeigen // 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; appInitialized = true;
} catch (e) { } catch (e) {
@@ -77,18 +118,9 @@ MainView {
} }
} }
Page {
id: mainPage
anchors.fill: parent
header: PageHeader {
title: "Fortune Cookie"
}
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")
@@ -171,10 +203,6 @@ MainView {
// ================================================================ // ================================================================
// MUSIK-BUTTON // 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 { Label {
id: musicButton id: musicButton
anchors { anchors {
@@ -184,12 +212,11 @@ MainView {
} }
width: units.gu(10) width: units.gu(10)
height: units.gu(10) height: units.gu(10)
text: musicPlaying ? "\uD83D\uDD0A" : "\uD83D\uDD07" // 🎵 oder 🔇 text: musicPlaying ? "\uD83D\uDD0A" : "\uD83D\uDD07"
fontSize: "xx-large" // Großes Icon für gute Sichtbarkeit fontSize: "xx-large"
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
color: theme.palette.normalText color: theme.palette.normalText
// FIX: Erst nach Initialisierung anzeigen
visible: appInitialized visible: appInitialized
MouseArea { MouseArea {
@@ -210,4 +237,15 @@ MainView {
} }
} }
} }
// ================================================================
// SEITE 1: EINSTELLUNGEN
// ================================================================
Settings {
id: settingsPage
// Zugriff auf Medien-Player ueber parent
property MediaPlayer settingsMediaPlayer: mainStack.stackMediaPlayer
property MediaPlayer settingsCrackPlayer: mainStack.stackCrackPlayer
}
}
} }
+210
View File
@@ -0,0 +1,210 @@
import QtQuick 2.7
import QtQuick.Controls 2.4
import QtQuick.Layouts 1.3
import Lomiri.Components 1.3
import Lomiri.Components.Popups 1.3
import io.thp.pyotherside 1.4
Page {
id: settingsPage
objectName: 'settingsPage'
property bool settingsInitialized: false
property var currentFortuneList: "classic"
property real musicVolume: 0.5
property real crackVolume: 1.0
header: PageHeader {
title: "Einstellungen"
}
// Timer für PyOtherSide Initialisierung
Timer {
id: initTimer
interval: 1000
running: true
repeat: false
onTriggered: {
try {
// Einstellungen laden
currentFortuneList = py.call_sync("fortunecookie.get_current_fortune_list", []);
musicVolume = py.call_sync("fortunecookie.get_music_volume", []);
crackVolume = py.call_sync("fortunecookie.get_crack_volume", []);
// Slider Werte setzen
musicVolumeSlider.value = musicVolume;
crackVolumeSlider.value = crackVolume;
// Spruchlisten ComboBox füllen
var lists = py.call_sync("fortunecookie.get_fortune_lists", []);
for (var i = 0; i < lists.length; i++) {
fortuneListCombo.model.append(lists[i]);
}
// Aktuelle Liste auswählen
for (var i = 0; i < fortuneListCombo.count; i++) {
if (fortuneListCombo.itemAt(i) === currentFortuneList) {
fortuneListCombo.currentIndex = i;
break;
}
}
settingsInitialized = true;
} catch (e) {
console.log("ERROR: Einstellungen nicht geladen: " + e);
}
}
}
Python {
id: py
Component.onCompleted: {
addImportPath(Qt.resolvedUrl("../src"));
importModule("fortunecookie", function() {
console.log("Python-Modul in Settings geladen");
});
}
}
ColumnLayout {
anchors.fill: parent
anchors.margins: units.gu(2)
spacing: units.gu(2)
// ============================================================
// SPRUCHLISTEN-AUSWAHL
// ============================================================
Label {
text: "Spruchliste:"
Layout.fillWidth: true
fontSize: "large"
}
ComboBox {
id: fortuneListCombo
Layout.fillWidth: true
Layout.preferredHeight: units.gu(8)
fontSize: "medium"
onActivated: {
var newList = fortuneListCombo.currentText;
py.call("fortunecookie.set_fortune_list", [newList], function() {
console.log("Spruchliste gewaehlt: " + newList);
});
}
}
// ============================================================
// LAUTSTÄRKE - MUSIK
// ============================================================
Label {
text: "Musik-Lautstärke:"
Layout.fillWidth: true
fontSize: "large"
}
RowLayout {
Layout.fillWidth: true
spacing: units.gu(2)
Slider {
id: musicVolumeSlider
Layout.fillWidth: true
minimumValue: 0.0
maximumValue: 1.0
stepSize: 0.1
value: 0.5
onMoved: {
var volume = musicVolumeSlider.value;
py.call("fortunecookie.set_music_volume", [volume]);
// Aktualisiere MediaPlayer ueber parent
if (parent && parent.parent && parent.parent.parent) {
var mainView = parent.parent.parent;
if (mainView && mainView.globalMediaPlayer) {
mainView.globalMediaPlayer.volume = volume;
}
}
musicVolumeLabel.text = Math.round(volume * 100) + "%";
}
}
Label {
id: musicVolumeLabel
text: Math.round(musicVolumeSlider.value * 100) + "%"
width: units.gu(10)
horizontalAlignment: Text.AlignHCenter
fontSize: "medium"
}
}
// ============================================================
// LAUTSTÄRKE - KNACK-GERÄUSCH
// ============================================================
Label {
text: "Knack-Lautstärke:"
Layout.fillWidth: true
fontSize: "large"
}
RowLayout {
Layout.fillWidth: true
spacing: units.gu(2)
Slider {
id: crackVolumeSlider
Layout.fillWidth: true
minimumValue: 0.0
maximumValue: 1.0
stepSize: 0.1
value: 1.0
onMoved: {
var volume = crackVolumeSlider.value;
py.call("fortunecookie.set_crack_volume", [volume]);
// Aktualisiere MediaPlayer ueber parent
if (parent && parent.parent && parent.parent.parent) {
var mainView = parent.parent.parent;
if (mainView && mainView.globalCrackPlayer) {
mainView.globalCrackPlayer.volume = volume;
}
}
crackVolumeLabel.text = Math.round(volume * 100) + "%";
}
}
Label {
id: crackVolumeLabel
text: Math.round(crackVolumeSlider.value * 100) + "%"
width: units.gu(10)
horizontalAlignment: Text.AlignHCenter
fontSize: "medium"
}
}
// ============================================================
// ZURÜCK-BUTTON
// ============================================================
Item {
Layout.fillWidth: true
Layout.preferredHeight: units.gu(10)
}
Button {
text: "Zurück"
Layout.fillWidth: false
Layout.preferredWidth: units.gu(20)
Layout.preferredHeight: units.gu(8)
Layout.alignment: Qt.AlignHCenter
onClicked: {
mainStack.currentIndex = 0;
}
}
}
}
+153 -85
View File
@@ -1,21 +1,21 @@
""" """
Fortune Cookie v1.0 - Python Backend Module Fortune Cookie v1.1 - Python Backend Module
Framework 1.7 Standard Framework 1.8 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 Last-State Speicherung mit Datei-basiertem Speicher
Einstellungen: Lautstaerke, Spruchlisten
""" """
import os import os
import random import random
import json import json
import platform import platform
from pathlib import Path
# ============================================================================ # ============================================================================
# APP-METADATEN # APP-METADATEN
# ============================================================================ # ============================================================================
APP_NAME = "fortunecookie" APP_NAME = "fortunecookie"
APP_VERSION = "1.0.0" APP_VERSION = "1.1.0"
MAINTAINER = "darklithium <dev@darklithium.de>" MAINTAINER = "darklithium <dev@darklithium.de>"
@@ -32,90 +32,107 @@ def get_platform():
# ============================================================================ # ============================================================================
# FORTUNE-LOGIK # FORTUNE-LISTEN VERWALTUNG
# ============================================================================ # ============================================================================
# Globale Variablen # Verfuegbare Spruchlisten
AVAILABLE_FORTUNE_LISTS = [
"classic", # Standard Glückskeks-Sprueche
"farmer_wisdom", # Bauernweisheiten
"unfortune", # Gothic/UNfortune-Sprueche
]
# Aktuelle Spruchliste (Standard: classic)
_current_fortune_list = "classic"
_current_fortune = "" _current_fortune = ""
_fortunes = [] _fortunes = {}
_initialized = False _initialized = False
def _init(): def _init():
"""Initialisiert das Modul (wird beim ersten Aufruf ausgefuehrt).""" """Initialisiert das Modul (wird beim ersten Aufruf ausgefuehrt)."""
global _fortunes, _initialized global _fortunes, _initialized, _current_fortune_list
if _initialized: if _initialized:
return True return True
# Lade Fortunes # Lade alle Spruchlisten
_load_fortunes() _load_all_fortune_lists()
# Lade aktuelle Liste aus Einstellungen
_current_fortune_list = load_setting("fortune_list", default_value="classic")
if _current_fortune_list not in _fortunes:
_current_fortune_list = "classic"
_initialized = True _initialized = True
return True return True
def _load_fortunes(): def _load_all_fortune_lists():
"""Laedt alle Sprueche aus assets/fortunes.json.""" """Laedt alle verfuegbaren Spruchlisten."""
global _fortunes global _fortunes
if _fortunes: if _fortunes:
return return
try: try:
# Versuche verschiedene Pfade base_path = os.path.join(os.path.dirname(__file__), "..", "assets", "fortunes")
possible_paths = [
os.path.join(os.path.dirname(__file__), "..", "assets", "fortunes.json"),
os.path.join("assets", "fortunes.json"),
]
for fortunes_path in possible_paths: for list_name in AVAILABLE_FORTUNE_LISTS:
if os.path.exists(fortunes_path): try:
with open(fortunes_path, "r", encoding="utf-8") as f: json_path = os.path.join(base_path, f"{list_name}.json")
data = json.load(f) if os.path.exists(json_path):
if isinstance(data, list): with open(json_path, "r", encoding="utf-8") as f:
_fortunes = data _fortunes[list_name] = json.load(f)
elif isinstance(data, dict): else:
# Lade deutsche Sprüche, falls vorhanden, sonst englische # Fallback: Leere Liste
_fortunes = data.get("de", data.get("en", [])) _fortunes[list_name] = []
elif isinstance(data, dict) and "fortunes" in data: except Exception as e:
_fortunes = data.get("fortunes", []) print(f"WARN: Spruchliste {list_name} nicht geladen: {e}")
return _fortunes[list_name] = []
except Exception as e:
print(f"ERROR: Spruchlisten nicht geladen: {e}")
# Fallback: Standard-Sprueche # Fallback: Standard-Sprueche
_fortunes = [ _fortunes = {
"classic": [
"Ein guter Tag beginnt mit einem Laecheln.", "Ein guter Tag beginnt mit einem Laecheln.",
"Das Glueck liegt in den kleinen Dingen.", "Das Glueck liegt in den kleinen Dingen.",
"Geduld ist eine Tugend.", "Geduld ist eine Tugend.",
] ],
"farmer_wisdom": [],
except Exception: "unfortune": []
_fortunes = [] }
def _get_random_fortune(): def _get_random_fortune():
"""Gibt einen zufaelligen Spruch zurueck.""" """Gibt einen zufaelligen Spruch aus der aktuellen Liste zurueck."""
if not _fortunes: global _current_fortune_list, _fortunes
_load_fortunes()
return random.choice(_fortunes) if _fortunes else "Keine Sprueche verfguebar." _init()
if _current_fortune_list not in _fortunes or not _fortunes[_current_fortune_list]:
# Fallback auf classic
_current_fortune_list = "classic"
if not _fortunes.get("classic"):
return "Keine Sprueche verfguebar."
return random.choice(_fortunes[_current_fortune_list])
def get_initial_fortune(): def get_initial_fortune():
"""Gibt einen zufaelligen Spruch fuer den Start zurueck.""" """Gibt einen zufaelligen Spruch fuer den Start zurueck."""
_init()
global _current_fortune global _current_fortune
_init()
_current_fortune = _get_random_fortune() _current_fortune = _get_random_fortune()
return _current_fortune return _current_fortune
def open_fortune(): def open_fortune():
"""Oeffnet den Fortune Cookie (neuer Spruch).""" """Oeffnet den Fortune Cookie (neuer Spruch aus aktueller Liste)."""
_init()
global _current_fortune global _current_fortune
_init()
# Neuer Spruch
_current_fortune = _get_random_fortune() _current_fortune = _get_random_fortune()
return True return True
@@ -128,23 +145,16 @@ def get_current_fortune():
def get_new_fortune(): def get_new_fortune():
"""Gibt einen neuen Spruch zurueck (Cookie schliesst sich).""" """Gibt einen neuen Spruch zurueck (Cookie schliesst sich)."""
_init()
global _current_fortune global _current_fortune
_init()
_current_fortune = _get_random_fortune() _current_fortune = _get_random_fortune()
return _current_fortune return _current_fortune
# ============================================================================ # ============================================================================
# LAST-STATE SPEICHERUNG (Musik an/aus) # EINSTELLUNGEN (Settings)
# ============================================================================ # ============================================================================
#
# 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 zurück (Click-App kompatibel).""" """Gibt das Konfigurationsverzeichnis zurück (Click-App kompatibel)."""
try: try:
@@ -154,42 +164,49 @@ def _get_config_dir():
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 für Tests
return os.path.join("/tmp", APP_NAME + "_config") return os.path.join("/tmp", APP_NAME + "_config")
def _get_state_file(state_name): def _get_setting_file(setting_name):
"""Gibt den Pfad zu einer Zustandsdatei zurück.""" """Gibt den Pfad zu einer Einstellungsdatei zurück."""
return os.path.join(_get_config_dir(), state_name) return os.path.join(_get_config_dir(), f"{setting_name}.txt")
def load_state(state_name, default_value=True): def load_setting(setting_name, default_value=None):
"""Lädt einen Zustand aus einer Datei. """Laedt eine Einstellung aus einer Datei.
Args: Args:
state_name (str): Name des Zustands setting_name (str): Name der Einstellung
default_value (bool): Standardwert, wenn Datei nicht existiert default_value: Standardwert, wenn Datei nicht existiert
Rückgabe: Rückgabe:
bool: Der geladene Zustand (True/False) Wert der Einstellung (Typ hängt von default_value ab)
""" """
try: try:
state_file = _get_state_file(state_name) setting_file = _get_setting_file(setting_name)
if os.path.exists(state_file): if os.path.exists(setting_file):
with open(state_file, "r") as f: with open(setting_file, "r") as f:
content = f.read().strip().lower() content = f.read().strip()
return content == "true" # Try to convert to appropriate type
if default_value is not None:
if isinstance(default_value, bool):
return content.lower() == "true"
elif isinstance(default_value, int):
return int(content)
elif isinstance(default_value, float):
return float(content)
return content
except Exception as e: except Exception as e:
print(f"WARN: Zustand nicht geladen ({state_name}): {e}") print(f"WARN: Einstellung nicht geladen ({setting_name}): {e}")
return default_value return default_value
def save_state(state_name, value): def save_setting(setting_name, value):
"""Speichert einen Zustand in einer Datei. """Speichert eine Einstellung in einer Datei.
Args: Args:
state_name (str): Name des Zustands setting_name (str): Name der Einstellung
value (bool): Der zu speichernde Zustand (True/False) value: Zu speichernder Wert (wird zu String konvertiert)
Rückgabe: Rückgabe:
bool: True bei Erfolg bool: True bei Erfolg
@@ -197,33 +214,84 @@ def save_state(state_name, value):
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_state_file(state_name) setting_file = _get_setting_file(setting_name)
with open(state_file, "w") as f: with open(setting_file, "w") as f:
f.write("true" if value else "false") f.write(str(value))
return True return True
except Exception as e: except Exception as e:
print(f"WARN: Zustand nicht gespeichert ({state_name}): {e}") print(f"WARN: Einstellung nicht gespeichert ({setting_name}): {e}")
return False return False
def get_music_enabled(): # ============================================================================
"""Gibt zurück, ob Musik aktiviert ist (Last-State). # LAUTSTÄRKE-EINSTELLUNGEN
# ============================================================================
Lädt den Zustand FRISCH aus der Datei bei jedem Aufruf. def get_music_volume():
""" """Gibt die Musik-Lautstärke zurück (0.0 - 1.0)."""
return load_state("music_enabled", default_value=True) return float(load_setting("music_volume", default_value=0.5))
def set_music_enabled(enabled): def set_music_volume(volume):
"""Setzt den Musik-Status und speichert ihn persistent. """Setzt die Musik-Lautstärke (0.0 - 1.0)."""
# Clamp value between 0.0 and 1.0
volume = max(0.0, min(1.0, float(volume)))
return save_setting("music_volume", volume)
def get_crack_volume():
"""Gibt die Knack-Lautstärke zurück (0.0 - 1.0)."""
return float(load_setting("crack_volume", default_value=1.0))
def set_crack_volume(volume):
"""Setzt die Knack-Lautstärke (0.0 - 1.0)."""
volume = max(0.0, min(1.0, float(volume)))
return save_setting("crack_volume", volume)
# ============================================================================
# SPRUCHLISTEN-EINSTELLUNGEN
# ============================================================================
def get_fortune_lists():
"""Gibt die Liste der verfuegbaren Spruchlisten zurück."""
_init()
return AVAILABLE_FORTUNE_LISTS
def get_current_fortune_list():
"""Gibt den Namen der aktuellen Spruchliste zurück."""
_init()
return load_setting("fortune_list", default_value="classic")
def set_fortune_list(list_name):
"""Setzt die aktuelle Spruchliste.
Args: Args:
enabled (bool): True = Musik an, False = Musik aus list_name (str): Name der Spruchliste (classic, farmer_wisdom, unfortune)
Rückgabe: Rückgabe:
bool: True bei Erfolg bool: True bei Erfolg
""" """
return save_state("music_enabled", enabled) if list_name not in AVAILABLE_FORTUNE_LISTS:
return False
return save_setting("fortune_list", list_name)
# ============================================================================
# MUSIK EIN/AUS (Last-State)
# ============================================================================
def get_music_enabled():
"""Gibt zurück, ob Musik aktiviert ist (Last-State)."""
return load_setting("music_enabled", default_value=True)
def set_music_enabled(enabled):
"""Setzt den Musik-Status und speichert ihn persistent."""
return save_setting("music_enabled", bool(enabled))
# ============================================================================ # ============================================================================