Android possible

main
joschy2002 2025-06-14 15:24:23 +02:00
parent b7ec276347
commit 753d6af4c5
12 changed files with 2659 additions and 48 deletions

View File

@ -10,16 +10,16 @@ plugins {
android { android {
namespace = "com.example.trainerbox" namespace = "com.example.trainerbox"
compileSdk = flutter.compileSdkVersion compileSdk = 35 // Aktualisiert auf SDK 35 für Plugin-Kompatibilität
ndkVersion = flutter.ndkVersion ndkVersion = "27.0.12077973" // Aktualisiert auf NDK 27.0.12077973 für Plugin-Kompatibilität
compileOptions { compileOptions {
sourceCompatibility = JavaVersion.VERSION_11 sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_1_8
} }
kotlinOptions { kotlinOptions {
jvmTarget = JavaVersion.VERSION_11.toString() jvmTarget = "1.8"
} }
defaultConfig { defaultConfig {
@ -27,21 +27,49 @@ android {
applicationId = "com.example.trainerbox" applicationId = "com.example.trainerbox"
// You can update the following values to match your application needs. // You can update the following values to match your application needs.
// For more information, see: https://flutter.dev/to/review-gradle-config. // For more information, see: https://flutter.dev/to/review-gradle-config.
minSdk = flutter.minSdkVersion minSdk = 21 // Mindest-SDK-Version für moderne Android-Geräte
targetSdk = flutter.targetSdkVersion targetSdk = 35 // Aktualisiert auf SDK 35
versionCode = flutter.versionCode versionCode = 1
versionName = flutter.versionName versionName = "1.0"
multiDexEnabled = true // Für Apps mit vielen Dependencies
} }
buildTypes { buildTypes {
release { release {
isMinifyEnabled = true // Code-Optimierung für Release-Builds
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
// TODO: Add your own signing config for the release build. // TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works. // Signing with the debug keys for now, so `flutter run --release` works.
signingConfig = signingConfigs.getByName("debug") signingConfig = signingConfigs.getByName("debug")
} }
} }
// Unterstützung für verschiedene Bildschirmgrößen
splits {
abi {
isEnable = true
reset()
include("armeabi-v7a", "arm64-v8a", "x86_64")
isUniversalApk = true
}
}
} }
flutter { flutter {
source = "../.." source = "../.."
} }
dependencies {
implementation(platform("com.google.firebase:firebase-bom:32.7.2"))
implementation("com.google.firebase:firebase-analytics")
implementation("com.google.firebase:firebase-auth")
implementation("com.google.firebase:firebase-firestore")
implementation("com.android.support:multidex:1.0.3")
implementation("androidx.core:core-ktx:1.12.0")
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("com.google.android.material:material:1.11.0")
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
implementation("com.google.firebase:firebase-core:21.1.1")
implementation("com.google.firebase:firebase-auth:22.3.1")
implementation("com.google.firebase:firebase-firestore:24.10.2")
}

View File

@ -1,12 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.CAMERA"/> <uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<application <application
android:label="TrainerBox"
android:name="${applicationName}" android:name="${applicationName}"
android:icon="@mipmap/ic_launcher"> android:icon="@mipmap/ic_launcher"
android:label="TrainerBox"
android:usesCleartextTraffic="true">
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:exported="true" android:exported="true"

View File

@ -1,4 +1,8 @@
{ {
"firestore": {
"rules": "firestore.rules",
"indexes": "firestore.indexes.json"
},
"flutter": { "flutter": {
"platforms": { "platforms": {
"android": { "android": {

View File

@ -0,0 +1,4 @@
{
"indexes": [],
"fieldOverrides": []
}

View File

@ -0,0 +1,24 @@
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Benutzer können ihre eigenen Daten lesen und schreiben
match /User/{userId} {
allow read, write: if request.auth != null && request.auth.uid == userId;
}
// Trainer können ihre eigenen Trainings verwalten
match /Training/{trainingId} {
allow read: if request.auth != null;
allow write: if request.auth != null &&
get(/databases/$(database)/documents/User/$(request.auth.uid)).data.role == 'trainer';
}
// Übungen können von allen gelesen werden
match /Exercise/{exerciseId} {
allow read: if request.auth != null;
allow write: if request.auth != null &&
get(/databases/$(database)/documents/User/$(request.auth.uid)).data.role == 'trainer';
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -26,6 +26,7 @@
buildConfiguration = "Debug" buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
shouldUseLaunchSchemeArgsEnv = "YES"> shouldUseLaunchSchemeArgsEnv = "YES">
<MacroExpansion> <MacroExpansion>
<BuildableReference <BuildableReference
@ -54,6 +55,7 @@
buildConfiguration = "Debug" buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
launchStyle = "0" launchStyle = "0"
useCustomWorkingDirectory = "NO" useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO" ignoresPersistentStateOnLaunch = "NO"

View File

@ -35,8 +35,6 @@
<key>UISupportedInterfaceOrientations</key> <key>UISupportedInterfaceOrientations</key>
<array> <array>
<string>UIInterfaceOrientationPortrait</string> <string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array> </array>
<key>UISupportedInterfaceOrientations~ipad</key> <key>UISupportedInterfaceOrientations~ipad</key>
<array> <array>
@ -49,5 +47,11 @@
<true/> <true/>
<key>UIApplicationSupportsIndirectInputEvents</key> <key>UIApplicationSupportsIndirectInputEvents</key>
<true/> <true/>
<key>UIRequiresFullScreen</key>
<true/>
<key>UIStatusBarHidden</key>
<false/>
<key>UIViewControllerBasedStatusBarAppearance</key>
<true/>
</dict> </dict>
</plist> </plist>

View File

@ -23,41 +23,96 @@ class _LoginScreenState extends State<LoginScreen> {
Future<void> _submit() async { Future<void> _submit() async {
setState(() { _loading = true; _error = null; }); setState(() { _loading = true; _error = null; });
try { try {
print('Login-Versuch gestartet...'); // Debug
if (_isLogin) { if (_isLogin) {
print('Login-Modus: E-Mail: ${_emailController.text.trim()}'); // Debug
// Login // Login
UserCredential cred = await FirebaseAuth.instance.signInWithEmailAndPassword( try {
email: _emailController.text.trim(), UserCredential cred = await FirebaseAuth.instance.signInWithEmailAndPassword(
password: _passwordController.text.trim(), email: _emailController.text.trim(),
); password: _passwordController.text.trim(),
// Firestore-Check );
final uid = cred.user!.uid; print('Firebase Auth erfolgreich: ${cred.user?.uid}'); // Debug
final userDoc = await FirebaseFirestore.instance.collection('User').doc(uid).get();
if (userDoc.exists) { // Firestore-Check
widget.onLoginSuccess(); final uid = cred.user!.uid;
} else { print('Firestore-Check für UID: $uid'); // Debug
setState(() { _error = 'Kein Benutzerprofil in der Datenbank gefunden!'; });
await FirebaseAuth.instance.signOut(); final userDoc = await FirebaseFirestore.instance.collection('User').doc(uid).get();
print('Firestore-Dokument existiert: ${userDoc.exists}'); // Debug
if (userDoc.exists) {
print('Login erfolgreich, Benutzer gefunden'); // Debug
widget.onLoginSuccess();
} else {
print('Kein Benutzerprofil in Firestore gefunden'); // Debug
setState(() { _error = 'Kein Benutzerprofil in der Datenbank gefunden!'; });
await FirebaseAuth.instance.signOut();
}
} catch (e) {
print('Fehler beim Firebase Auth: $e'); // Debug
rethrow;
} }
} else { } else {
print('Registrierungs-Modus: E-Mail: ${_emailController.text.trim()}'); // Debug
// Registrierung // Registrierung
UserCredential cred = await FirebaseAuth.instance.createUserWithEmailAndPassword( try {
email: _emailController.text.trim(), UserCredential cred = await FirebaseAuth.instance.createUserWithEmailAndPassword(
password: _passwordController.text.trim(), email: _emailController.text.trim(),
); password: _passwordController.text.trim(),
// User-Datensatz in Firestore anlegen );
final uid = cred.user!.uid; print('Firebase Auth Registrierung erfolgreich: ${cred.user?.uid}'); // Debug
await FirebaseFirestore.instance.collection('User').doc(uid).set({
'email': _emailController.text.trim(), // User-Datensatz in Firestore anlegen
'name': _nameController.text.trim(), final uid = cred.user!.uid;
'role': _isTrainer ? 'trainer' : 'player', print('Erstelle Firestore-Dokument für UID: $uid'); // Debug
'createdAt': FieldValue.serverTimestamp(),
}); await FirebaseFirestore.instance.collection('User').doc(uid).set({
widget.onLoginSuccess(); 'email': _emailController.text.trim(),
'name': _nameController.text.trim(),
'role': _isTrainer ? 'trainer' : 'player',
'createdAt': FieldValue.serverTimestamp(),
});
print('Firestore-Dokument erstellt'); // Debug
widget.onLoginSuccess();
} catch (e) {
print('Fehler bei der Registrierung: $e'); // Debug
rethrow;
}
} }
} on FirebaseAuthException catch (e) { } on FirebaseAuthException catch (e) {
setState(() { _error = e.message ?? 'Fehler'; }); print('FirebaseAuthException: ${e.code} - ${e.message}'); // Debug
String errorMessage;
switch (e.code) {
case 'user-not-found':
errorMessage = 'Kein Benutzer mit dieser E-Mail-Adresse gefunden.';
break;
case 'wrong-password':
errorMessage = 'Falsches Passwort.';
break;
case 'invalid-email':
errorMessage = 'Ungültige E-Mail-Adresse.';
break;
case 'user-disabled':
errorMessage = 'Dieser Account wurde deaktiviert.';
break;
case 'email-already-in-use':
errorMessage = 'Diese E-Mail-Adresse wird bereits verwendet.';
break;
case 'weak-password':
errorMessage = 'Das Passwort ist zu schwach.';
break;
case 'operation-not-allowed':
errorMessage = 'Diese Operation ist nicht erlaubt.';
break;
default:
errorMessage = 'Ein Fehler ist aufgetreten: ${e.message}';
}
setState(() { _error = errorMessage; });
} catch (e) { } catch (e) {
setState(() { _error = 'Unbekannter Fehler'; }); print('Unerwarteter Fehler: $e'); // Debug
setState(() { _error = 'Ein unerwarteter Fehler ist aufgetreten. Bitte versuchen Sie es später erneut.'; });
} finally { } finally {
setState(() { _loading = false; }); setState(() { _loading = false; });
} }

View File

@ -0,0 +1,55 @@
import 'package:flutter/material.dart';
class Responsive {
static bool isMobile(BuildContext context) =>
MediaQuery.of(context).size.width < 600;
static bool isTablet(BuildContext context) =>
MediaQuery.of(context).size.width >= 600 &&
MediaQuery.of(context).size.width < 1200;
static bool isDesktop(BuildContext context) =>
MediaQuery.of(context).size.width >= 1200;
static double getWidth(BuildContext context) =>
MediaQuery.of(context).size.width;
static double getHeight(BuildContext context) =>
MediaQuery.of(context).size.height;
static double getScaledWidth(BuildContext context, double percentage) =>
getWidth(context) * (percentage / 100);
static double getScaledHeight(BuildContext context, double percentage) =>
getHeight(context) * (percentage / 100);
static EdgeInsets getPadding(BuildContext context) {
if (isMobile(context)) {
return const EdgeInsets.all(16.0);
} else if (isTablet(context)) {
return const EdgeInsets.all(24.0);
} else {
return const EdgeInsets.all(32.0);
}
}
static double getFontSize(BuildContext context, double baseSize) {
if (isMobile(context)) {
return baseSize;
} else if (isTablet(context)) {
return baseSize * 1.2;
} else {
return baseSize * 1.4;
}
}
static double getIconSize(BuildContext context, double baseSize) {
if (isMobile(context)) {
return baseSize;
} else if (isTablet(context)) {
return baseSize * 1.2;
} else {
return baseSize * 1.4;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -13,10 +13,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: async name: async
sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63 sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.12.0" version: "2.13.0"
boolean_selector: boolean_selector:
dependency: transitive dependency: transitive
description: description:
@ -101,10 +101,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: fake_async name: fake_async
sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc" sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.3.2" version: "1.3.3"
file_selector_linux: file_selector_linux:
dependency: transitive dependency: transitive
description: description:
@ -340,10 +340,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: leak_tracker name: leak_tracker
sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "10.0.8" version: "10.0.9"
leak_tracker_flutter_testing: leak_tracker_flutter_testing:
dependency: transitive dependency: transitive
description: description:
@ -537,10 +537,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: vm_service name: vm_service
sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14" sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "14.3.1" version: "15.0.0"
web: web:
dependency: transitive dependency: transitive
description: description: