Android possible
parent
b7ec276347
commit
753d6af4c5
|
|
@ -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")
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,8 @@
|
||||||
{
|
{
|
||||||
|
"firestore": {
|
||||||
|
"rules": "firestore.rules",
|
||||||
|
"indexes": "firestore.indexes.json"
|
||||||
|
},
|
||||||
"flutter": {
|
"flutter": {
|
||||||
"platforms": {
|
"platforms": {
|
||||||
"android": {
|
"android": {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"indexes": [],
|
||||||
|
"fieldOverrides": []
|
||||||
|
}
|
||||||
|
|
@ -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
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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; });
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
@ -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:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue