feat: add exercise informations and first l10n strings
This commit is contained in:
parent
253f694424
commit
bf9a54c8b1
8 changed files with 900 additions and 59 deletions
203
lib/l10n/app_de.arb
Normal file
203
lib/l10n/app_de.arb
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
{
|
||||
"enterTheArena": "BETRITT DIE ARENA",
|
||||
"introText": "Die Eisengolems sind erwacht. Die Schwerkraft-Dämonen ziehen die Welt in den Abgrund.\n\nNur ein wahrer Streetlifter kann sie aufhalten. Bist du bereit, deinen Körper in eine Waffe zu schmieden?",
|
||||
"featureArmorTitle": "Schmiede deine Rüstung",
|
||||
"featureArmorDesc": "Progressive Overload basierend auf Wendler 5/3/1.",
|
||||
"featureMonstersTitle": "Erschlage Monster",
|
||||
"featureMonstersDesc": "Verwandle jede Wiederholung in Schaden gegen epische Feinde.",
|
||||
"featureLootTitle": "Sammle Beute",
|
||||
"featureLootDesc": "Verdiene XP, steige auf und schalte neue Ausrüstung frei.",
|
||||
"beginJourney": "BEGINNE DEINE REISE",
|
||||
"loginPrompt": "Schon ein Held? Hier einloggen",
|
||||
|
||||
"loginWelcomeBack": "WILLKOMMEN ZURÜCK",
|
||||
"loginSubtitle": "Zeit für das nächste Level",
|
||||
"loginErrorInvalid": "Ungültige E-Mail oder Passwort",
|
||||
"loginErrorConnection": "Keine Verbindung zum Server.\nBitte prüfe deine Internetverbindung.",
|
||||
"loginErrorTimeout": "Zeitüberschreitung.\nBitte versuche es erneut.",
|
||||
"loginErrorGeneric": "Login fehlgeschlagen. Bitte erneut versuchen.",
|
||||
"emailLabel": "E-Mail",
|
||||
"emailEmptyError": "Bitte gib deine E-Mail ein",
|
||||
"emailInvalidError": "Bitte gib eine gültige E-Mail ein",
|
||||
"passwordLabel": "Passwort",
|
||||
"passwordEmptyError": "Bitte gib dein Passwort ein",
|
||||
"passwordLengthError": "Passwort muss mindestens 8 Zeichen haben",
|
||||
"loginButton": "ANMELDEN",
|
||||
"loginNoAccount": "Kein Account? ",
|
||||
"loginRegisterButton": "REGISTRIEREN",
|
||||
|
||||
"registerTitle": "KONTO ERSTELLEN",
|
||||
"registerSubtitle": "Beginne deine Reise",
|
||||
"registerEmailHelper": "Wird für den Login verwendet",
|
||||
"continueButton": "WEITER",
|
||||
"registerHaveAccount": "Bereits registriert? ",
|
||||
"registerLoginButton": "LOGIN",
|
||||
|
||||
"hubNoActiveCycle": "Kein aktiver Zyklus",
|
||||
"hubCreateCycle": "Neuen Zyklus starten",
|
||||
"hubCycleLabel": "Zyklus",
|
||||
"hubActiveLabel": "Aktiv",
|
||||
"hubActiveYes": "Ja",
|
||||
"navHistory": "Historie",
|
||||
"navInventory": "Inventar",
|
||||
"navStats": "Statistik",
|
||||
"navCodex": "Kodex",
|
||||
"missionBriefingTitle": "MISSION BRIEFING",
|
||||
"missionBriefingBody": "Der Feind flieht! Wir haben ein 20-Minuten-Fenster, um ihn abzufangen.",
|
||||
"missionBriefingDensity": "Kampfdichte: {sets} Sätze",
|
||||
"@missionBriefingDensity": {
|
||||
"placeholders": {
|
||||
"sets": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"missionBriefingInterval": "Intervall: Alle {seconds} Sekunden",
|
||||
"@missionBriefingInterval": {
|
||||
"placeholders": {
|
||||
"seconds": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"missionBriefingHardcore": "⚠️ HARDCORE MODUS",
|
||||
"abortButton": "ABBRECHEN",
|
||||
"engageButton": "ANGREIFEN",
|
||||
|
||||
"inventoryTitle": "Ausrüstung verwalten",
|
||||
"saveButton": "SPEICHERN",
|
||||
"inventoryBarbellWeight": "Hantelstangengewicht",
|
||||
"inventoryPresets": "Schnellwahl",
|
||||
"inventoryPresetHome": "Home Gym",
|
||||
"inventoryPresetCommercial": "Fitnessstudio",
|
||||
"inventoryPresetMinimal": "Minimal",
|
||||
"inventoryPlates": "Verfügbare Scheiben",
|
||||
"inventoryBands": "Widerstandsbänder (Hilfe)",
|
||||
"saveChangesButton": "ÄNDERUNGEN SPEICHERN",
|
||||
"inventoryUpdatedSuccess": "Inventar erfolgreich aktualisiert",
|
||||
"inventorySaveError": "Fehler beim Speichern: {error}",
|
||||
"@inventorySaveError": {
|
||||
"placeholders": {
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"statsTitle": "Statistik & Zyklen",
|
||||
"statsProgressAnalysis": "Fortschrittsanalyse",
|
||||
"statsCycleTitle": "ZYKLUS {number}",
|
||||
"@statsCycleTitle": {
|
||||
"placeholders": {
|
||||
"number": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"statsCurrentTM": "Aktuelle Trainingsmaxima (TM)",
|
||||
"statsFinishCycle": "ZYKLUS BEENDEN & LEVEL UP",
|
||||
"statsCycleFinishedTitle": "Dungeon gesäubert!",
|
||||
"statsCycleFinishedBody": "Du hast die Wächter dieses Zyklus besiegt. Doch tiefer im Dungeon warten stärkere Feinde...",
|
||||
"statsTMIncreased": "Deine Trainingsmaxima wurden erhöht:",
|
||||
"statsStalled": "STAGNIERT",
|
||||
"statsEnterNextLevel": "NÄCHSTES LEVEL BETRETEN",
|
||||
|
||||
"historyTitle": "Quest Log",
|
||||
"historyEmptyTitle": "Noch keine Quests abgeschlossen",
|
||||
"historyEmptyBody": "Absolviere ein Training, um dein Journal zu füllen",
|
||||
"historyUnknownWorkout": "Unbekanntes Training",
|
||||
|
||||
"battleWave": "WELLE {current} / {total}",
|
||||
"@battleWave": {
|
||||
"placeholders": {
|
||||
"current": {"type": "int"},
|
||||
"total": {"type": "int"}
|
||||
}
|
||||
},
|
||||
"battleSet": "Satz {current} von {total}",
|
||||
"@battleSet": {
|
||||
"placeholders": {
|
||||
"current": {"type": "int"},
|
||||
"total": {"type": "int"}
|
||||
}
|
||||
},
|
||||
"battleWeight": "GEWICHT",
|
||||
"battleReps": "WH",
|
||||
"battleAssistance": "UNTERSTÜTZUNG",
|
||||
"battleCompleteSet": "SATZ ABSCHLIESSEN",
|
||||
"battleRest": "PAUSE",
|
||||
"battleSkipRest": "WEITER",
|
||||
"battleUpNext": "NÄCHSTES: {exercise}",
|
||||
"@battleUpNext": {
|
||||
"placeholders": {
|
||||
"exercise": {"type": "String"}
|
||||
}
|
||||
},
|
||||
"battleRaidComplete": "RAID ERFOLGREICH!",
|
||||
"battleBackToHub": "ZUR ZENTRALE",
|
||||
"levelUpTitle": "LEVEL AUFSTIEG!",
|
||||
"levelUpBody": "Du bist stärker geworden!",
|
||||
"levelUpSubtitle": "Die Monster erzittern vor deiner neuen Macht.",
|
||||
"battleAbandonTitle": "Raid abbrechen?",
|
||||
"battleAbandonBody": "Dein Fortschritt wird nicht gespeichert.",
|
||||
"cancelButton": "ABBRECHEN",
|
||||
"abandonButton": "AUFGEBEN",
|
||||
"amrapResultTitle": "🔥 AMRAP ERGEBNIS 🔥",
|
||||
"amrapResultBody": "Alles gegeben! Wie viele waren es?",
|
||||
"amrapConfirm": "ERGEBNIS BESTÄTIGEN",
|
||||
"emomFinishedTitle": "MISSION ERFÜLLT",
|
||||
"emomFinishedBody": "Die Zeit ist um. Hast du durchgehalten?",
|
||||
"emomSetsCompleted": "SÄTZE ABGESCHLOSSEN",
|
||||
"emomConfirm": "BESTÄTIGEN & BEENDEN",
|
||||
"emomRepsPerRound": "Wiederholungen pro Runde",
|
||||
|
||||
"questTabDailies": "TÄGLICH",
|
||||
"questTabJourney": "REISE",
|
||||
"questEmptyDailies": "Keine täglichen Quests.\nKomm morgen wieder!",
|
||||
"questEmptyJourney": "Deine Reise hat gerade erst begonnen.",
|
||||
|
||||
"setupProfileTitle": "Profil einrichten",
|
||||
"bodyweightTitle": "Wie schwer bist du aktuell?",
|
||||
"bodyweightSubtitle": "Wir benötigen dies zur Berechnung deiner Weighted Calisthenics Übungen",
|
||||
"unitKg": "KG",
|
||||
"unitLbs": "LBS",
|
||||
|
||||
"strengthTestTitle": "Stärke-Test",
|
||||
"strengthTestSubtitle": "Kampf-Kalibrierung",
|
||||
"strengthTestBody": "Wir müssen dein aktuelles Kraftlevel ermitteln, um die richtigen Monster zuzuweisen.",
|
||||
"strengthLegs": "Beinkraft",
|
||||
"strengthPull": "Zugkraft (Pull)",
|
||||
"strengthPush": "Druckkraft (Push)",
|
||||
"exerciseSquat": "Kniebeuge (Back Squat)",
|
||||
"exercisePullup": "Weighted Pull-up",
|
||||
"exerciseRow": "Pendlay Row",
|
||||
"exerciseDip": "Weighted Dip",
|
||||
"exerciseBench": "Bankdrücken",
|
||||
"canDoOneRep": "Schaffst du 1 Rep?",
|
||||
"isAssisted": "Mit Band-Hilfe?",
|
||||
"addWeightLabel": "Zusatzgewicht (kg)",
|
||||
"weightLabel": "Gewicht (kg)",
|
||||
"bandAssistanceLabel": "Band-Hilfe (kg)",
|
||||
"rowWeightLabel": "Ruder-Gewicht (kg)",
|
||||
"repsLabel": "Wiederholungen",
|
||||
"reps5rmLabel": "5RM Wiederholungen (meist 5)",
|
||||
"est1rm": "Geschätztes 1RM",
|
||||
"trainingMaxLabel": "Trainingsmaximum (90%)",
|
||||
"adjustedWendler": "Angepasst: Wendler 5/3/1",
|
||||
"tmExplanation": "Dein \"Trainingsmaximum\" (TM) ist deine Basis-Kampfkraft (90% vom 1RM). Bei Eigengewichtsübungen passen wir die Strategie an.",
|
||||
|
||||
"setupEquipmentTitle": "Ausrüstung Setup",
|
||||
"setupInventoryTitle": "Ausrüstungsinventar",
|
||||
"setupInventorySubtitle": "Sag uns, welche Ausrüstung du hast",
|
||||
"setupBandsSubtitle": "Wähle Bänder für Pullup/Dip Unterstützung",
|
||||
"nextStepButton": "NÄCHSTER SCHRITT",
|
||||
|
||||
"setupAvatarTitle": "Wähle deinen Helden",
|
||||
"finishButton": "FERTIGSTELLEN",
|
||||
"setupAvatarSubtitle": "So werden dich die Legenden in Erinnerung behalten.",
|
||||
"secureAccountTitle": "Konto sichern",
|
||||
"secureAccountBody": "Wähle ein starkes Passwort, um deinen Fortschritt zu schützen",
|
||||
"confirmPasswordLabel": "Passwort bestätigen",
|
||||
"passwordsDoNotMatch": "Passwörter stimmen nicht überein",
|
||||
"confirmButton": "BESTÄTIGEN"
|
||||
}
|
||||
203
lib/l10n/app_en.arb
Normal file
203
lib/l10n/app_en.arb
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
{
|
||||
"enterTheArena": "ENTER THE ARENA",
|
||||
"introText": "The Iron Golems have awakened. The Gravity Demons are pulling the world into the abyss.\n\nOnly a true Streetlifter can stop them. Are you ready to forge your body into a weapon?",
|
||||
"featureArmorTitle": "Build Your Armor",
|
||||
"featureArmorDesc": "Progressive overload based on Wendler 5/3/1.",
|
||||
"featureMonstersTitle": "Slay Monsters",
|
||||
"featureMonstersDesc": "Turn every rep into damage against epic foes.",
|
||||
"featureLootTitle": "Gather Loot",
|
||||
"featureLootDesc": "Earn XP, level up, and unlock new gear.",
|
||||
"beginJourney": "BEGIN YOUR JOURNEY",
|
||||
"loginPrompt": "Already a hero? Login here",
|
||||
|
||||
"loginWelcomeBack": "WELCOME BACK",
|
||||
"loginSubtitle": "Time to level up your strength",
|
||||
"loginErrorInvalid": "Invalid email or password",
|
||||
"loginErrorConnection": "Could not connect to server.\nPlease check your internet connection.",
|
||||
"loginErrorTimeout": "Connection timeout.\nPlease try again.",
|
||||
"loginErrorGeneric": "Login failed. Please try again.",
|
||||
"emailLabel": "Email",
|
||||
"emailEmptyError": "Please enter your email",
|
||||
"emailInvalidError": "Please enter a valid email",
|
||||
"passwordLabel": "Password",
|
||||
"passwordEmptyError": "Please enter your password",
|
||||
"passwordLengthError": "Password must be at least 8 characters",
|
||||
"loginButton": "LOGIN",
|
||||
"loginNoAccount": "Don't have an account? ",
|
||||
"loginRegisterButton": "REGISTER",
|
||||
|
||||
"registerTitle": "CREATE ACCOUNT",
|
||||
"registerSubtitle": "Begin your strength journey",
|
||||
"registerEmailHelper": "You will use this to login",
|
||||
"continueButton": "CONTINUE",
|
||||
"registerHaveAccount": "Already have an account? ",
|
||||
"registerLoginButton": "LOGIN",
|
||||
|
||||
"hubNoActiveCycle": "No active cycle",
|
||||
"hubCreateCycle": "Create New Cycle",
|
||||
"hubCycleLabel": "Cycle",
|
||||
"hubActiveLabel": "Active",
|
||||
"hubActiveYes": "Yes",
|
||||
"navHistory": "History",
|
||||
"navInventory": "Inventory",
|
||||
"navStats": "Stats",
|
||||
"navCodex": "Codex",
|
||||
"missionBriefingTitle": "MISSION BRIEFING",
|
||||
"missionBriefingBody": "The enemy is fleeing! We have a 20-minute window to intercept.",
|
||||
"missionBriefingDensity": "Combat Density: {sets} Sets",
|
||||
"@missionBriefingDensity": {
|
||||
"placeholders": {
|
||||
"sets": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"missionBriefingInterval": "Interval: Every {seconds} seconds",
|
||||
"@missionBriefingInterval": {
|
||||
"placeholders": {
|
||||
"seconds": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"missionBriefingHardcore": "⚠️ HARDCORE MODE",
|
||||
"abortButton": "ABORT",
|
||||
"engageButton": "ENGAGE",
|
||||
|
||||
"inventoryTitle": "Manage Equipment",
|
||||
"saveButton": "SAVE",
|
||||
"inventoryBarbellWeight": "Barbell Weight",
|
||||
"inventoryPresets": "Quick Presets",
|
||||
"inventoryPresetHome": "Home Gym",
|
||||
"inventoryPresetCommercial": "Commercial",
|
||||
"inventoryPresetMinimal": "Minimal",
|
||||
"inventoryPlates": "Plates Available",
|
||||
"inventoryBands": "Resistance Bands (Assistance)",
|
||||
"saveChangesButton": "SAVE CHANGES",
|
||||
"inventoryUpdatedSuccess": "Inventory updated successfully",
|
||||
"inventorySaveError": "Error saving: {error}",
|
||||
"@inventorySaveError": {
|
||||
"placeholders": {
|
||||
"error": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"statsTitle": "Statistics & Cycles",
|
||||
"statsProgressAnalysis": "Progress Analysis",
|
||||
"statsCycleTitle": "CYCLE {number}",
|
||||
"@statsCycleTitle": {
|
||||
"placeholders": {
|
||||
"number": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"statsCurrentTM": "Current Training Maxes (TM)",
|
||||
"statsFinishCycle": "FINISH CYCLE & LEVEL UP",
|
||||
"statsCycleFinishedTitle": "Dungeon Cleared!",
|
||||
"statsCycleFinishedBody": "You have defeated the guardians of this cycle. But deeper in the dungeon, stronger foes await...",
|
||||
"statsTMIncreased": "Your Training Maxes have increased:",
|
||||
"statsStalled": "STALLED",
|
||||
"statsEnterNextLevel": "ENTER NEXT LEVEL",
|
||||
|
||||
"historyTitle": "Quest Log",
|
||||
"historyEmptyTitle": "No completed quests yet",
|
||||
"historyEmptyBody": "Complete a workout to fill your journal",
|
||||
"historyUnknownWorkout": "Unknown Workout",
|
||||
|
||||
"battleWave": "WAVE {current} / {total}",
|
||||
"@battleWave": {
|
||||
"placeholders": {
|
||||
"current": {"type": "int"},
|
||||
"total": {"type": "int"}
|
||||
}
|
||||
},
|
||||
"battleSet": "Set {current} of {total}",
|
||||
"@battleSet": {
|
||||
"placeholders": {
|
||||
"current": {"type": "int"},
|
||||
"total": {"type": "int"}
|
||||
}
|
||||
},
|
||||
"battleWeight": "WEIGHT",
|
||||
"battleReps": "REPS",
|
||||
"battleAssistance": "ASSISTANCE",
|
||||
"battleCompleteSet": "COMPLETE SET",
|
||||
"battleRest": "REST",
|
||||
"battleSkipRest": "SKIP REST",
|
||||
"battleUpNext": "UP NEXT: {exercise}",
|
||||
"@battleUpNext": {
|
||||
"placeholders": {
|
||||
"exercise": {"type": "String"}
|
||||
}
|
||||
},
|
||||
"battleRaidComplete": "RAID COMPLETE!",
|
||||
"battleBackToHub": "BACK TO HUB",
|
||||
"levelUpTitle": "LEVEL UP!",
|
||||
"levelUpBody": "You have grown stronger!",
|
||||
"levelUpSubtitle": "The monsters tremble at your new power.",
|
||||
"battleAbandonTitle": "Abandon Raid?",
|
||||
"battleAbandonBody": "Your progress will not be saved.",
|
||||
"cancelButton": "CANCEL",
|
||||
"abandonButton": "ABANDON",
|
||||
"amrapResultTitle": "🔥 AMRAP RESULT 🔥",
|
||||
"amrapResultBody": "Go all out! How many did you get?",
|
||||
"amrapConfirm": "CONFIRM RESULT",
|
||||
"emomFinishedTitle": "MISSION ACCOMPLISHED",
|
||||
"emomFinishedBody": "Time is up. Did you push further?",
|
||||
"emomSetsCompleted": "SETS COMPLETED",
|
||||
"emomConfirm": "CONFIRM & FINISH",
|
||||
"emomRepsPerRound": "Reps per Round",
|
||||
|
||||
"questTabDailies": "DAILIES",
|
||||
"questTabJourney": "JOURNEY",
|
||||
"questEmptyDailies": "No daily quests available.\nCome back tomorrow!",
|
||||
"questEmptyJourney": "Your journey has just begun.",
|
||||
|
||||
"setupProfileTitle": "Setup Profile",
|
||||
"bodyweightTitle": "What's your current bodyweight?",
|
||||
"bodyweightSubtitle": "We need this to calculate your weighted calisthenics exercises",
|
||||
"unitKg": "KG",
|
||||
"unitLbs": "LBS",
|
||||
|
||||
"strengthTestTitle": "Strength Test",
|
||||
"strengthTestSubtitle": "Combat Calibration",
|
||||
"strengthTestBody": "We need to assess your current power level to assign the correct monsters.",
|
||||
"strengthLegs": "Leg Strength",
|
||||
"strengthPull": "Pull Strength",
|
||||
"strengthPush": "Push Strength",
|
||||
"exerciseSquat": "Back Squat",
|
||||
"exercisePullup": "Weighted Pull-up",
|
||||
"exerciseRow": "Pendlay Row",
|
||||
"exerciseDip": "Weighted Dip",
|
||||
"exerciseBench": "Bench Press",
|
||||
"canDoOneRep": "Can do 1 rep?",
|
||||
"isAssisted": "Assisted (Bands)?",
|
||||
"addWeightLabel": "Add. Weight (kg)",
|
||||
"weightLabel": "Weight (kg)",
|
||||
"bandAssistanceLabel": "Band Assistance (kg)",
|
||||
"rowWeightLabel": "Row Weight (kg)",
|
||||
"repsLabel": "Reps",
|
||||
"reps5rmLabel": "5RM Reps (usually 5)",
|
||||
"est1rm": "Est. 1RM",
|
||||
"trainingMaxLabel": "Training Max (90%)",
|
||||
"adjustedWendler": "Adjusted: Wendler 5/3/1",
|
||||
"tmExplanation": "Your \"Training Max\" (TM) is your base combat power (90% of 1RM). For bodyweight exercises, we adjust the strategy.",
|
||||
|
||||
"setupEquipmentTitle": "Equipment Setup",
|
||||
"setupInventoryTitle": "Equipment Inventory",
|
||||
"setupInventorySubtitle": "Tell us what equipment you have available",
|
||||
"setupBandsSubtitle": "Select bands you have for pullup/dip assistance",
|
||||
"nextStepButton": "NEXT STEP",
|
||||
|
||||
"setupAvatarTitle": "Choose Your Hero",
|
||||
"finishButton": "FINISH",
|
||||
"setupAvatarSubtitle": "This is how the legends will remember you.",
|
||||
"secureAccountTitle": "Secure Your Account",
|
||||
"secureAccountBody": "Choose a strong password to protect your progress",
|
||||
"confirmPasswordLabel": "Confirm Password",
|
||||
"passwordsDoNotMatch": "Passwords do not match",
|
||||
"confirmButton": "CONFIRM"
|
||||
}
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:slrpg_app/l10n/app_localizations.dart';
|
||||
|
||||
import 'core/theme/app_theme.dart';
|
||||
import 'core/routing/app_router.dart';
|
||||
|
|
@ -17,7 +19,16 @@ class SLRPGApp extends ConsumerWidget {
|
|||
debugShowCheckedModeBanner: false,
|
||||
theme: AppTheme.darkTheme,
|
||||
routerConfig: router,
|
||||
localizationsDelegates: const [
|
||||
AppLocalizations.delegate,
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
],
|
||||
supportedLocales: const [
|
||||
Locale('en'),
|
||||
Locale('de'),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:slrpg_app/l10n/app_localizations.dart';
|
||||
|
||||
import '../../../../core/theme/app_theme.dart';
|
||||
import '../../../../core/constants/asset_paths.dart';
|
||||
|
|
@ -9,6 +10,8 @@ class WelcomeScreen extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
|
||||
return Scaffold(
|
||||
body: Stack(
|
||||
children: [
|
||||
|
|
@ -48,7 +51,7 @@ class WelcomeScreen extends StatelessWidget {
|
|||
),
|
||||
const SizedBox(height: 32),
|
||||
Text(
|
||||
'ENTER THE ARENA',
|
||||
l10n.enterTheArena,
|
||||
style: Theme.of(context).textTheme.headlineMedium?.copyWith(
|
||||
color: Colors.white70,
|
||||
letterSpacing: 2,
|
||||
|
|
@ -67,9 +70,8 @@ class WelcomeScreen extends StatelessWidget {
|
|||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const Text(
|
||||
'The Iron Golems have awakened. The Gravity Demons are pulling the world into the abyss.\n\n'
|
||||
'Only a true Streetlifter can stop them. Are you ready to forge your body into a weapon?',
|
||||
Text(
|
||||
l10n.introText,
|
||||
style: TextStyle(
|
||||
fontSize: 16, height: 1.5, color: Colors.white),
|
||||
textAlign: TextAlign.center,
|
||||
|
|
@ -77,21 +79,20 @@ class WelcomeScreen extends StatelessWidget {
|
|||
const SizedBox(height: 48),
|
||||
_FeatureItem(
|
||||
icon: Icons.shield,
|
||||
title: 'Build Your Armor',
|
||||
description: 'Progressive overload based on Wendler 5/3/1.',
|
||||
title: l10n.featureArmorTitle,
|
||||
description: l10n.featureArmorDesc,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
_FeatureItem(
|
||||
icon: Icons.videogame_asset,
|
||||
title: 'Slay Monsters',
|
||||
description:
|
||||
'Turn every rep into damage against epic foes.',
|
||||
title: l10n.featureMonstersTitle,
|
||||
description: l10n.featureMonstersDesc,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
_FeatureItem(
|
||||
icon: Icons.inventory_2,
|
||||
title: 'Gather Loot',
|
||||
description: 'Earn XP, level up, and unlock new gear.',
|
||||
title: l10n.featureLootTitle,
|
||||
description: l10n.featureLootDesc,
|
||||
),
|
||||
const Spacer(),
|
||||
ElevatedButton(
|
||||
|
|
@ -100,14 +101,14 @@ class WelcomeScreen extends StatelessWidget {
|
|||
backgroundColor: AppTheme.primaryColor,
|
||||
padding: const EdgeInsets.symmetric(vertical: 20),
|
||||
),
|
||||
child: const Text('BEGIN YOUR JOURNEY',
|
||||
child: Text(l10n.beginJourney,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold, letterSpacing: 1)),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
TextButton(
|
||||
onPressed: () => context.go('/login'),
|
||||
child: const Text('Already a hero? Login here',
|
||||
child: Text(l10n.loginPrompt,
|
||||
style: TextStyle(color: Colors.white54)),
|
||||
),
|
||||
],
|
||||
|
|
|
|||
|
|
@ -0,0 +1,210 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import '../../../../core/theme/app_theme.dart';
|
||||
import '../../../../shared/domain/models/exercise_guide.dart';
|
||||
|
||||
class ExerciseGuideSheet extends StatelessWidget {
|
||||
final String exerciseId;
|
||||
|
||||
const ExerciseGuideSheet({super.key, required this.exerciseId});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
String lookupId = exerciseId;
|
||||
if (exerciseId.contains('kb_snatch')) lookupId = 'kb_snatch';
|
||||
// Weitere Mappings hier falls nötig...
|
||||
|
||||
final guide = exerciseLibrary[lookupId];
|
||||
|
||||
if (guide == null) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(32),
|
||||
child: const Text('No ancient scroll found for this technique.',
|
||||
textAlign: TextAlign.center, style: TextStyle(color: Colors.grey)),
|
||||
);
|
||||
}
|
||||
|
||||
return DraggableScrollableSheet(
|
||||
initialChildSize: 0.85,
|
||||
minChildSize: 0.5,
|
||||
maxChildSize: 0.95,
|
||||
builder: (context, scrollController) {
|
||||
return Container(
|
||||
decoration: const BoxDecoration(
|
||||
color: AppTheme.surfaceColor,
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(24)),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
const SizedBox(height: 12),
|
||||
Container(
|
||||
width: 40,
|
||||
height: 4,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey[700],
|
||||
borderRadius: BorderRadius.circular(2),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: ListView(
|
||||
controller: scrollController,
|
||||
padding: const EdgeInsets.all(24),
|
||||
children: [
|
||||
Text(
|
||||
guide.title.toUpperCase(),
|
||||
style:
|
||||
Theme.of(context).textTheme.headlineMedium?.copyWith(
|
||||
color: AppTheme.primaryColor,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
_buildDifficultyBadge(guide.difficulty),
|
||||
const SizedBox(height: 24),
|
||||
Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: AppTheme.backgroundColor,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(color: Colors.white12),
|
||||
),
|
||||
child: Text(
|
||||
'"${guide.rpgLore}"',
|
||||
style: const TextStyle(
|
||||
fontStyle: FontStyle.italic,
|
||||
color: AppTheme.textSecondary,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 32),
|
||||
_buildSectionTitle(context, 'EXECUTION'),
|
||||
const SizedBox(height: 16),
|
||||
...guide.steps
|
||||
.asMap()
|
||||
.entries
|
||||
.map((entry) => _buildStep(entry.key + 1, entry.value)),
|
||||
const SizedBox(height: 32),
|
||||
_buildSectionTitle(context, 'COMMON MISTAKES'),
|
||||
const SizedBox(height: 16),
|
||||
...guide.commonMistakes.map((m) => _buildMistake(m)),
|
||||
const SizedBox(height: 32),
|
||||
_buildSectionTitle(context, 'ATTRIBUTES AFFECTED'),
|
||||
const SizedBox(height: 16),
|
||||
Wrap(
|
||||
spacing: 8,
|
||||
runSpacing: 8,
|
||||
children: guide.muscles
|
||||
.map((m) => Chip(
|
||||
label: Text(m),
|
||||
backgroundColor: AppTheme.primaryColor
|
||||
.withValues(alpha: 0.1),
|
||||
labelStyle: const TextStyle(
|
||||
color: AppTheme.primaryColor),
|
||||
side: BorderSide.none,
|
||||
))
|
||||
.toList(),
|
||||
),
|
||||
const SizedBox(height: 40),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDifficultyBadge(String diff) {
|
||||
Color color;
|
||||
switch (diff) {
|
||||
case 'Novice':
|
||||
color = Colors.green;
|
||||
break;
|
||||
case 'Adept':
|
||||
color = Colors.orange;
|
||||
break;
|
||||
case 'Master':
|
||||
color = AppTheme.errorColor;
|
||||
break;
|
||||
default:
|
||||
color = Colors.grey;
|
||||
}
|
||||
|
||||
return Center(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: color.withValues(alpha: 0.2),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(color: color.withValues(alpha: 0.5)),
|
||||
),
|
||||
child: Text(
|
||||
diff.toUpperCase(),
|
||||
style: TextStyle(
|
||||
color: color, fontSize: 12, fontWeight: FontWeight.bold),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSectionTitle(BuildContext context, String title) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.bold,
|
||||
letterSpacing: 1.2,
|
||||
),
|
||||
),
|
||||
const Divider(
|
||||
color: AppTheme.primaryColor, thickness: 2, endIndent: 250),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildStep(int index, String text) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 12.0),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
width: 24,
|
||||
height: 24,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
color: AppTheme.primaryColor,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Text('$index',
|
||||
style: const TextStyle(
|
||||
color: Colors.black, fontWeight: FontWeight.bold)),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: Text(text,
|
||||
style: const TextStyle(color: Colors.white70, height: 1.4))),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildMistake(String text) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8.0),
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(Icons.close, color: AppTheme.errorColor, size: 20),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Text(text, style: const TextStyle(color: Colors.white70))),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -20,6 +20,7 @@ import '../widgets/enemy_hp_bar.dart';
|
|||
import '../../../gamification/application/quest_service.dart';
|
||||
import '../widgets/emom_timer_widget.dart';
|
||||
import '../widgets/timer_widget.dart';
|
||||
import '../../../wiki/presentation/widgets/exercise_guide_sheet.dart';
|
||||
|
||||
class BattleScreen extends ConsumerStatefulWidget {
|
||||
final int week;
|
||||
|
|
@ -105,6 +106,15 @@ class _BattleScreenState extends ConsumerState<BattleScreen> {
|
|||
}
|
||||
}
|
||||
|
||||
void _showExerciseGuide(String exerciseId) {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
backgroundColor: Colors.transparent,
|
||||
builder: (context) => ExerciseGuideSheet(exerciseId: exerciseId),
|
||||
);
|
||||
}
|
||||
|
||||
List<Map<String, dynamic>> _getExerciseConfig(int day, UserCollection user) {
|
||||
final variants = user.exerciseVariants ?? {};
|
||||
|
||||
|
|
@ -875,6 +885,13 @@ class _BattleScreenState extends ConsumerState<BattleScreen> {
|
|||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.info_outline,
|
||||
color: Colors.white54),
|
||||
onPressed: () =>
|
||||
_showExerciseGuide(currentExercise.exerciseId),
|
||||
),
|
||||
Text(
|
||||
'Set ${_currentSetIndex + 1} of ${currentExercise.sets.length}',
|
||||
style: Theme.of(context)
|
||||
|
|
@ -1108,6 +1125,14 @@ class _BattleScreenState extends ConsumerState<BattleScreen> {
|
|||
fontSize: 16,
|
||||
color: Colors.white),
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.info_outline,
|
||||
size: 20, color: AppTheme.primaryColor),
|
||||
onPressed: () =>
|
||||
_showExerciseGuide(currentExercise.exerciseId),
|
||||
padding: const EdgeInsets.all(4),
|
||||
constraints: const BoxConstraints(),
|
||||
),
|
||||
Text(
|
||||
'${currentSet.repsTarget} Reps per Round',
|
||||
style: const TextStyle(color: Colors.grey),
|
||||
|
|
|
|||
233
lib/src/shared/domain/models/exercise_guide.dart
Normal file
233
lib/src/shared/domain/models/exercise_guide.dart
Normal file
|
|
@ -0,0 +1,233 @@
|
|||
import '../logic/wendler_calculator.dart';
|
||||
|
||||
class ExerciseGuide {
|
||||
final String title;
|
||||
final String difficulty; // z.B. "Novice", "Adept", "Master"
|
||||
final String rpgLore; // Ein kleiner Flavor-Text
|
||||
final List<String> steps;
|
||||
final List<String> muscles;
|
||||
final List<String> commonMistakes;
|
||||
|
||||
const ExerciseGuide({
|
||||
required this.title,
|
||||
required this.difficulty,
|
||||
required this.rpgLore,
|
||||
required this.steps,
|
||||
required this.muscles,
|
||||
required this.commonMistakes,
|
||||
});
|
||||
}
|
||||
|
||||
final Map<String, ExerciseGuide> exerciseLibrary = {
|
||||
'pullup': const ExerciseGuide(
|
||||
title: 'Weighted Pull-Up',
|
||||
difficulty: 'Adept',
|
||||
rpgLore:
|
||||
'Den Körper gegen die Schwerkraft zu ziehen, ist der ultimative Beweis für Oberkörperkraft.',
|
||||
steps: [
|
||||
'Greife die Stange etwas weiter als schulterbreit (Obergriff).',
|
||||
'Aktiviere den Core und ziehe die Schulterblätter nach unten/hinten.',
|
||||
'Ziehe dich hoch, bis das Kinn über der Stange ist.',
|
||||
'Lasse dich kontrolliert wieder ab.',
|
||||
],
|
||||
muscles: ['Latissimus', 'Bizeps', 'Unterarme'],
|
||||
commonMistakes: [
|
||||
'Schwingen (Kipping)',
|
||||
'Halbe Wiederholungen',
|
||||
'Schultern hochgezogen lassen'
|
||||
],
|
||||
),
|
||||
'dip': const ExerciseGuide(
|
||||
title: 'Weighted Dip',
|
||||
difficulty: 'Adept',
|
||||
rpgLore: 'Ein fundamentaler Druck-Move, um Mauern zu überwinden.',
|
||||
steps: [
|
||||
'Stütze dich auf die Barren, Arme gestreckt.',
|
||||
'Lehne dich leicht nach vorne für mehr Brust-Fokus.',
|
||||
'Senke den Körper ab, bis die Schultern unter den Ellbogen sind.',
|
||||
'Drücke dich explosiv zurück in die Ausgangsposition.',
|
||||
],
|
||||
muscles: ['Brust', 'Trizeps', 'Vordere Schulter'],
|
||||
commonMistakes: ['Zu wenig Tiefe', 'Ellbogen wandern zu weit nach außen'],
|
||||
),
|
||||
'squat': const ExerciseGuide(
|
||||
title: 'Low Bar Back Squat',
|
||||
difficulty: 'Master',
|
||||
rpgLore:
|
||||
'Die Mutter aller Schlachten. Trainiert den gesamten Körperpanzer.',
|
||||
steps: [
|
||||
'Lege die Hantel auf dem hinteren Deltamuskel ab (nicht im Nacken).',
|
||||
'Füße schulterbreit, Zehen leicht nach außen.',
|
||||
'Atme tief ein (Bracing) und schiebe die Hüfte nach hinten.',
|
||||
'Gehe in die Hocke (Hüfte unter Kniehöhe).',
|
||||
'Drücke dich aus der Ferse/Mittelfuß wieder hoch.',
|
||||
],
|
||||
muscles: ['Quadrizeps', 'Gesäß', 'Core', 'Rückenstrecker'],
|
||||
commonMistakes: [
|
||||
'Knie fallen nach innen',
|
||||
'Rücken rundet ein',
|
||||
'Zu wenig Tiefe'
|
||||
],
|
||||
),
|
||||
'bench': const ExerciseGuide(
|
||||
title: 'Bench Press',
|
||||
difficulty: 'Novice',
|
||||
rpgLore: 'Der Standard-Test für reine Druckkraft.',
|
||||
steps: [
|
||||
'Lege dich auf die Bank, Augen unter der Stange.',
|
||||
'Füße fest am Boden, leichter Bogen im Rücken (Brücke).',
|
||||
'Senke die Hantel kontrolliert zur unteren Brust.',
|
||||
'Drücke die Hantel explosiv nach oben.',
|
||||
],
|
||||
muscles: ['Brust', 'Trizeps', 'Vordere Schulter'],
|
||||
commonMistakes: [
|
||||
'Ellbogen 90° abgespreizt (Verletzungsgefahr)',
|
||||
'Hintern hebt ab'
|
||||
],
|
||||
),
|
||||
'ohp': const ExerciseGuide(
|
||||
title: 'Overhead Press',
|
||||
difficulty: 'Adept',
|
||||
rpgLore: 'Ein Objekt über den Kopf zu stemmen erfordert pure Stabilität.',
|
||||
steps: [
|
||||
'Stange liegt auf dem vorderen Schultermuskel.',
|
||||
'Fester Stand, Gesäß und Bauch maximal anspannen.',
|
||||
'Kopf leicht zurücknehmen, Stange vertikal nach oben drücken.',
|
||||
'Oben den Kopf "durch das Fenster" der Arme schieben.',
|
||||
],
|
||||
muscles: ['Schultern', 'Trizeps', 'Core'],
|
||||
commonMistakes: ['Hohlkreuz (Rücklage)', 'Beine helfen mit (Push Press)'],
|
||||
),
|
||||
'rdl': const ExerciseGuide(
|
||||
title: 'Romanian Deadlift',
|
||||
difficulty: 'Adept',
|
||||
rpgLore: 'Baut die hintere Kette auf, essenziell für Stabilität.',
|
||||
steps: [
|
||||
'Startposition stehend mit Hantel.',
|
||||
'Schiebe die Hüfte weit nach hinten, Beine bleiben fast gestreckt.',
|
||||
'Senke die Hantel am Bein entlang bis knapp unter das Knie.',
|
||||
'Spüre den Zug im Beinbeuger und richte dich wieder auf.',
|
||||
],
|
||||
muscles: ['Beinbeuger (Hamstrings)', 'Gesäß', 'Unterer Rücken'],
|
||||
commonMistakes: ['Rücken rundet ein', 'Hantel zu weit vom Körper weg'],
|
||||
),
|
||||
'row': const ExerciseGuide(
|
||||
title: 'Pendlay Row',
|
||||
difficulty: 'Adept',
|
||||
rpgLore: 'Explosive Zugkraft vom Boden. Für einen starken Rücken.',
|
||||
steps: [
|
||||
'Oberkörper parallel zum Boden, Rücken gerade.',
|
||||
'Hantel liegt bei jeder Wiederholung tot auf dem Boden.',
|
||||
'Ziehe die Hantel explosiv zum unteren Brustbein.',
|
||||
'Kontrolliert ablegen, Spannung kurz lösen, neu ansetzen.',
|
||||
],
|
||||
muscles: ['Latissimus', 'Trapez', 'Hintere Schulter'],
|
||||
commonMistakes: ['Oberkörper richtet sich auf', 'Reißen mit Schwung'],
|
||||
),
|
||||
'curl': const ExerciseGuide(
|
||||
title: 'Barbell Curl',
|
||||
difficulty: 'Novice',
|
||||
rpgLore: 'Isolierte Kraft für den finalen Schlag.',
|
||||
steps: [
|
||||
'Stehender Stand, Hantel im Untergriff.',
|
||||
'Ellbogen bleiben fixiert am Körper.',
|
||||
'Hantel zur Brust curlen, oben kurz halten.',
|
||||
'Langsam ablassen.',
|
||||
],
|
||||
muscles: ['Bizeps'],
|
||||
commonMistakes: ['Schwingen aus der Hüfte', 'Ellbogen wandern nach vorne'],
|
||||
),
|
||||
'kb_swing': const ExerciseGuide(
|
||||
title: 'Kettlebell Swing',
|
||||
difficulty: 'Adept',
|
||||
rpgLore: 'Ballistische Kraft und Ausdauer. Die Hüfte ist der Motor.',
|
||||
steps: [
|
||||
'Hüftbreiter Stand, KB vor dir am Boden.',
|
||||
'Hike-Pass: Ziehe die KB durch die Beine nach hinten.',
|
||||
'Hüfte explosiv strecken (Snap!), KB fliegt durch Hüftkraft auf Brusthöhe.',
|
||||
'KB kontrolliert zurückschwingen lassen.',
|
||||
],
|
||||
muscles: ['Gesäß', 'Beinbeuger', 'Core', 'Ausdauer'],
|
||||
commonMistakes: ['Kniebeuge statt Hüftbeuge', 'Arme heben das Gewicht'],
|
||||
),
|
||||
'kb_snatch': const ExerciseGuide(
|
||||
title: 'Kettlebell Snatch',
|
||||
difficulty: 'Master',
|
||||
rpgLore: 'Der Zar der Kettlebell-Übungen. Totale Körperkontrolle.',
|
||||
steps: [
|
||||
'Starte wie beim Swing (Einarmig).',
|
||||
'Hüftkraft beschleunigt die Kugel nach oben.',
|
||||
'Bei Kopfhöhe: Durchstoßen der Hand ("Punch through").',
|
||||
'Sanftes Auffangen im Lockout über Kopf.',
|
||||
],
|
||||
muscles: ['Gesamter Körper', 'Schultern', 'Griffkraft'],
|
||||
commonMistakes: ['Kugel knallt auf den Unterarm', 'Zu wenig Hüftkraft'],
|
||||
),
|
||||
'kb_thruster': const ExerciseGuide(
|
||||
title: 'Kettlebell Thruster',
|
||||
difficulty: 'Master',
|
||||
rpgLore: 'Eine brutale Kombination aus Squat und Press.',
|
||||
steps: [
|
||||
'KB in der Rack-Position (vor der Brust).',
|
||||
'Tiefe Kniebeuge.',
|
||||
'Beim Aufstehen den Schwung nutzen, um KB über Kopf zu drücken.',
|
||||
'Zurück in die Rack-Position beim Absenken in den nächsten Squat.',
|
||||
],
|
||||
muscles: ['Beine', 'Schultern', 'Lunge (Cardio)'],
|
||||
commonMistakes: [
|
||||
'Pause zwischen Squat und Press',
|
||||
'Rücken rundet im Squat'
|
||||
],
|
||||
),
|
||||
'kb_clean_press': const ExerciseGuide(
|
||||
title: 'KB Clean & Press',
|
||||
difficulty: 'Adept',
|
||||
rpgLore: 'Zwei Bewegungen in Harmonie.',
|
||||
steps: [
|
||||
'Clean: Ziehe die KB vom Boden in die Rack-Position vor der Brust.',
|
||||
'Press: Drücke sie strikt über den Kopf.',
|
||||
'Senke sie in Rack, dann zum Boden (oder Swing).',
|
||||
],
|
||||
muscles: ['Schultern', 'Rücken', 'Beine'],
|
||||
commonMistakes: ['Clean knallt auf Arm', 'Hohlkreuz beim Press'],
|
||||
),
|
||||
'face_pull': const ExerciseGuide(
|
||||
title: 'Band Face Pull',
|
||||
difficulty: 'Novice',
|
||||
rpgLore: 'Schützt die Schultern vor dem Verschleiß des Kampfes.',
|
||||
steps: [
|
||||
'Band auf Kopfhöhe befestigen.',
|
||||
'Ziehe das Band zum Gesicht (Richtung Stirn/Augen).',
|
||||
'Ellbogen hoch und weit nach außen ziehen.',
|
||||
'Schulterblätter hinten zusammenkneifen.',
|
||||
],
|
||||
muscles: ['Hintere Schulter', 'Rotatorenmanschette'],
|
||||
commonMistakes: ['Ellbogen zu tief', 'Kopf nach vorne schieben'],
|
||||
),
|
||||
'ab_wheel': const ExerciseGuide(
|
||||
title: 'Ab Wheel Rollout',
|
||||
difficulty: 'Adept',
|
||||
rpgLore: 'Ein Stahlkern, der jeden Treffer absorbiert.',
|
||||
steps: [
|
||||
'Knie am Boden, Rad vor den Knien.',
|
||||
'Rolle nach vorne, halte den Rücken rund/stabil (Hollow Body).',
|
||||
'Gehe nur so weit, wie du den Rücken stabil halten kannst.',
|
||||
'Ziehe dich aus dem Bauchmuskel zurück.',
|
||||
],
|
||||
muscles: ['Core (Anti-Extension)'],
|
||||
commonMistakes: ['Hohlkreuz (Gefährlich!)', 'Ziehen aus den Armen'],
|
||||
),
|
||||
'plank': const ExerciseGuide(
|
||||
title: 'Plank',
|
||||
difficulty: 'Novice',
|
||||
rpgLore: 'Unbeweglich wie ein Fels in der Brandung.',
|
||||
steps: [
|
||||
'Unterarmstütz, Körper bildet eine Linie.',
|
||||
'Gesäß und Bauch fest anspannen.',
|
||||
'Schulterblätter auseinanderdrücken.',
|
||||
'Atmen nicht vergessen!',
|
||||
],
|
||||
muscles: ['Core'],
|
||||
commonMistakes: ['Hüfte hängt durch', 'Gesäß zu hoch'],
|
||||
),
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue