add login and input
This commit is contained in:
parent
2f844fcaef
commit
ee655328e6
@ -3,4 +3,5 @@ APPWRITE_PROJECT_NAME=<Your Project Name>
|
|||||||
APPWRITE_PROJECT_ID=<Your Project Id>
|
APPWRITE_PROJECT_ID=<Your Project Id>
|
||||||
APPWRITE_DATABASE_ID=<Your Database Id>
|
APPWRITE_DATABASE_ID=<Your Database Id>
|
||||||
APPWRITE_COLLECTION_ID=<Your Collection id>
|
APPWRITE_COLLECTION_ID=<Your Collection id>
|
||||||
|
APPWRITE_SELF_SIGNED=<true>
|
||||||
PTVE_API_KEY=<Your PTV API key Geolocation Address>
|
PTVE_API_KEY=<Your PTV API key Geolocation Address>
|
||||||
25
.vscode/launch.json
vendored
Normal file
25
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
// Verwendet IntelliSense zum Ermitteln möglicher Attribute.
|
||||||
|
// Zeigen Sie auf vorhandene Attribute, um die zugehörigen Beschreibungen anzuzeigen.
|
||||||
|
// Weitere Informationen finden Sie unter https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "web_flutter_tank_appwrite_app",
|
||||||
|
"request": "launch",
|
||||||
|
"type": "dart"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "web_flutter_tank_appwrite_app (profile mode)",
|
||||||
|
"request": "launch",
|
||||||
|
"type": "dart",
|
||||||
|
"flutterMode": "profile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "web_flutter_tank_appwrite_app (release mode)",
|
||||||
|
"request": "launch",
|
||||||
|
"type": "dart",
|
||||||
|
"flutterMode": "release"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
18
lib/bindings/input_binding.dart
Normal file
18
lib/bindings/input_binding.dart
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import 'package:get/get.dart';
|
||||||
|
import '../controllers/input_controller.dart';
|
||||||
|
|
||||||
|
class InputBinding extends Bindings {
|
||||||
|
@override
|
||||||
|
void dependencies() {
|
||||||
|
Get.lazyPut<InputController>(() => InputController());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Alternative: Permanent Binding für App-weite Nutzung
|
||||||
|
class InputPermanentBinding extends Bindings {
|
||||||
|
@override
|
||||||
|
void dependencies() {
|
||||||
|
// Permanent - Controller bleibt im Speicher
|
||||||
|
Get.put<InputController>(InputController(), permanent: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
17
lib/controllers/input_controller.dart
Normal file
17
lib/controllers/input_controller.dart
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
|
class InputController extends GetxController {
|
||||||
|
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onInit() {
|
||||||
|
super.onInit();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onReady() {}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onClose() {}
|
||||||
|
|
||||||
|
}
|
||||||
@ -4,6 +4,7 @@ import 'package:flutter/cupertino.dart';
|
|||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:appwrite/appwrite.dart';
|
import 'package:appwrite/appwrite.dart';
|
||||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
|
||||||
class LoginController extends GetxController {
|
class LoginController extends GetxController {
|
||||||
final _account = Rxn<account_models.Account>();
|
final _account = Rxn<account_models.Account>();
|
||||||
@ -12,40 +13,123 @@ class LoginController extends GetxController {
|
|||||||
final nameController = TextEditingController();
|
final nameController = TextEditingController();
|
||||||
final _endpoint = dotenv.env['APPWRITE_ENDPOINT_URL'] ?? '';
|
final _endpoint = dotenv.env['APPWRITE_ENDPOINT_URL'] ?? '';
|
||||||
final _projectId = dotenv.env['APPWRITE_PROJECT_ID'] ?? '';
|
final _projectId = dotenv.env['APPWRITE_PROJECT_ID'] ?? '';
|
||||||
|
final bool _selfSigned =
|
||||||
|
(dotenv.env['APPWRITE_SELF_SIGNED'] ?? 'false').toLowerCase() == 'true';
|
||||||
final _logedInUser = Rxn<user_models.User>();
|
final _logedInUser = Rxn<user_models.User>();
|
||||||
|
final formKey = GlobalKey<FormState>();
|
||||||
|
final isLogIn = false.obs;
|
||||||
|
|
||||||
account_models.Account? get account => _account.value;
|
account_models.Account? get account => _account.value;
|
||||||
user_models.User? get logedInUser => _logedInUser.value;
|
user_models.User? get logedInUser => _logedInUser.value;
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onInit() {
|
void onInit() {
|
||||||
Client client = Client()
|
Client client = Client().setEndpoint(_endpoint).setProject(_projectId);
|
||||||
.setEndpoint(_endpoint)
|
// Optional: Unsichere/self-signed Zertifikate im Dev zulassen (nicht im Web wirksam)
|
||||||
.setProject(_projectId);
|
if (!kIsWeb && _selfSigned) {
|
||||||
|
client.setSelfSigned(status: true);
|
||||||
|
}
|
||||||
_account.value = Account(client);
|
_account.value = Account(client);
|
||||||
super.onInit();
|
super.onInit();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> login(String email, String password) async {
|
emailValidator(String? value) {
|
||||||
await _account.value!.createEmailPasswordSession(
|
if (value == null || value.isEmpty) {
|
||||||
email: email,
|
return 'Please enter your email';
|
||||||
password: password,
|
}
|
||||||
);
|
final emailRegex = RegExp(r'^[^@]+@[^@]+\.[^@]+');
|
||||||
final user = await _account.value!.get();
|
if (!emailRegex.hasMatch(value)) {
|
||||||
|
return 'Please enter a valid email address';
|
||||||
_logedInUser.value = user;
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> register(String email, String password, String name) async {
|
passwordValidator(String? value) {
|
||||||
|
if (value == null || value.isEmpty) {
|
||||||
|
return 'Please enter your password';
|
||||||
|
}
|
||||||
|
if (value.length < 6) {
|
||||||
|
return 'Password must be at least 6 characters long';
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
nameValidator(String? value) {
|
||||||
|
if (value == null || value.isEmpty) {
|
||||||
|
return 'Please enter your name';
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> login() async {
|
||||||
|
try {
|
||||||
|
var result = await _account.value!.createEmailPasswordSession(
|
||||||
|
email: mailController.text,
|
||||||
|
password: passwordController.text,
|
||||||
|
);
|
||||||
|
// ignore: avoid_print
|
||||||
|
print('Login result: $result');
|
||||||
|
final user = await _account.value!.get();
|
||||||
|
_logedInUser.value = user;
|
||||||
|
clearFields();
|
||||||
|
Get.snackbar(
|
||||||
|
'Erfolg',
|
||||||
|
'Anmeldung erfolgreich',
|
||||||
|
snackPosition: SnackPosition.BOTTOM,
|
||||||
|
);
|
||||||
|
} on AppwriteException catch (e) {
|
||||||
|
final msg = (e.message == null || e.message!.isEmpty)
|
||||||
|
? 'Verbindungsfehler. Prüfe Zertifikat/Endpoint.'
|
||||||
|
: e.message!;
|
||||||
|
Get.snackbar(
|
||||||
|
'Login fehlgeschlagen',
|
||||||
|
msg,
|
||||||
|
snackPosition: SnackPosition.BOTTOM,
|
||||||
|
duration: const Duration(seconds: 5),
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
Get.snackbar(
|
||||||
|
'Login fehlgeschlagen',
|
||||||
|
e.toString(),
|
||||||
|
snackPosition: SnackPosition.BOTTOM,
|
||||||
|
duration: const Duration(seconds: 5),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clearFields(){
|
||||||
|
mailController.clear();
|
||||||
|
passwordController.clear();
|
||||||
|
nameController.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> register() async {
|
||||||
|
try {
|
||||||
await _account.value!.create(
|
await _account.value!.create(
|
||||||
userId: ID.unique(),
|
userId: ID.unique(),
|
||||||
email: email,
|
email: mailController.text,
|
||||||
password: password,
|
password: passwordController.text,
|
||||||
name: name,
|
name: nameController.text,
|
||||||
);
|
);
|
||||||
await login(email, password);
|
await login();
|
||||||
|
} on AppwriteException catch (e) {
|
||||||
|
final msg = (e.message == null || e.message!.isEmpty)
|
||||||
|
? 'Registrierung fehlgeschlagen. Prüfe Verbindung.'
|
||||||
|
: e.message!;
|
||||||
|
Get.snackbar(
|
||||||
|
'Registrierung fehlgeschlagen',
|
||||||
|
msg,
|
||||||
|
snackPosition: SnackPosition.BOTTOM,
|
||||||
|
duration: const Duration(seconds: 5),
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
Get.snackbar(
|
||||||
|
'Registrierung fehlgeschlagen',
|
||||||
|
e.toString(),
|
||||||
|
snackPosition: SnackPosition.BOTTOM,
|
||||||
|
duration: const Duration(seconds: 5),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> logout() async {
|
Future<void> logout() async {
|
||||||
@ -53,8 +137,6 @@ class LoginController extends GetxController {
|
|||||||
_logedInUser.value = null;
|
_logedInUser.value = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onClose() {
|
void onClose() {
|
||||||
mailController.dispose();
|
mailController.dispose();
|
||||||
@ -63,3 +145,4 @@ class LoginController extends GetxController {
|
|||||||
super.onClose();
|
super.onClose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
0
lib/models/input_model.dart
Normal file
0
lib/models/input_model.dart
Normal file
14
lib/pages/input/input_view.dart
Normal file
14
lib/pages/input/input_view.dart
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import '../../controllers/input_controller.dart';
|
||||||
|
|
||||||
|
class InputPage extends GetView<InputController> {
|
||||||
|
const InputPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
body: Container(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,14 +1,129 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import '../../controllers/login_controller.dart';
|
import '../../controllers/login_controller.dart';
|
||||||
|
import '../../widgets/my_form_field.dart';
|
||||||
|
|
||||||
class LoginPage extends GetView<LoginController> {
|
class LoginPage extends GetView<LoginController> {
|
||||||
const LoginPage({super.key});
|
const LoginPage({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
var logCtrl = controller;
|
||||||
body: Container(color: Colors.red.shade300, child: Center(child: Text('Login Page')),),
|
var displaySize = MediaQuery.of(context).size;
|
||||||
|
return PopScope(
|
||||||
|
canPop: false,
|
||||||
|
child: SafeArea(
|
||||||
|
child: Scaffold(
|
||||||
|
body: Container(
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
image: DecorationImage(
|
||||||
|
image: AssetImage('assets/img/gasolineGuru.jpg'),
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// Optional: Für besseren Kontrast Inhalt leicht abdunkeln
|
||||||
|
child: Container(
|
||||||
|
color: Colors.black.withValues(alpha: 0.25),
|
||||||
|
child: Center(
|
||||||
|
child: SizedBox(
|
||||||
|
width: displaySize.width * 2 / 3,
|
||||||
|
child: Form(
|
||||||
|
key: logCtrl.formKey,
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
Icons.local_gas_station,
|
||||||
|
size: 100,
|
||||||
|
color: Colors.grey.shade300,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
_eMailForm(logCtrl),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
_passwdForm(logCtrl),
|
||||||
|
SizedBox(height: 20),
|
||||||
|
Obx(
|
||||||
|
() => !logCtrl.isLogIn.value
|
||||||
|
? SizedBox.shrink()
|
||||||
|
: _nameForm(logCtrl),
|
||||||
|
),
|
||||||
|
SizedBox(height: 20),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () async {
|
||||||
|
if (logCtrl.formKey.currentState!.validate()) {
|
||||||
|
if (!logCtrl.isLogIn.value) {
|
||||||
|
await logCtrl.login();
|
||||||
|
} else {
|
||||||
|
await logCtrl.register();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: Obx(
|
||||||
|
() => Text(
|
||||||
|
!logCtrl.isLogIn.value ? 'Login' : 'Register',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
logCtrl.isLogIn.value = !logCtrl.isLogIn.value;
|
||||||
|
},
|
||||||
|
child: Obx(
|
||||||
|
() => Text(
|
||||||
|
!logCtrl.isLogIn.value
|
||||||
|
? 'No account? Register'
|
||||||
|
: 'Already have an account? Login',
|
||||||
|
style: TextStyle(color: Colors.grey.shade300),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
// Hier können Sie Ihre Login-Felder hinzufügen
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
MyFormField _passwdForm(LoginController logCtrl) {
|
||||||
|
return MyFormField(
|
||||||
|
userController: logCtrl.passwordController,
|
||||||
|
validator: (String? value) => logCtrl.passwordValidator(value) as String?,
|
||||||
|
labelText: 'Password',
|
||||||
|
filled: true,
|
||||||
|
fillColor: Colors.grey.shade300,
|
||||||
|
keyboardType: TextInputType.visiblePassword,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
MyFormField _eMailForm(LoginController logCtrl) {
|
||||||
|
return MyFormField(
|
||||||
|
userController: logCtrl.mailController,
|
||||||
|
validator: (String? value) => logCtrl.emailValidator(value) as String?,
|
||||||
|
labelText: 'E-Mail',
|
||||||
|
filled: true,
|
||||||
|
fillColor: Colors.grey.shade300,
|
||||||
|
keyboardType: TextInputType.emailAddress,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
_nameForm(LoginController logCtrl) {
|
||||||
|
return MyFormField(
|
||||||
|
userController: logCtrl.nameController,
|
||||||
|
validator: (String? value) => logCtrl.nameValidator(value) as String?,
|
||||||
|
labelText: 'Name',
|
||||||
|
filled: true,
|
||||||
|
fillColor: Colors.grey.shade300,
|
||||||
|
keyboardType: TextInputType.name,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
37
lib/widgets/my_form_field.dart
Normal file
37
lib/widgets/my_form_field.dart
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class MyFormField extends StatelessWidget {
|
||||||
|
const MyFormField({
|
||||||
|
super.key,
|
||||||
|
this.validator,
|
||||||
|
required this.labelText,
|
||||||
|
required this.filled,
|
||||||
|
required this.fillColor,
|
||||||
|
required this.keyboardType,
|
||||||
|
required this.userController,
|
||||||
|
});
|
||||||
|
|
||||||
|
final TextEditingController userController;
|
||||||
|
final String labelText;
|
||||||
|
final bool filled;
|
||||||
|
final Color fillColor;
|
||||||
|
final TextInputType keyboardType;
|
||||||
|
final String? Function(String?)? validator;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return TextFormField(
|
||||||
|
autovalidateMode: AutovalidateMode.onUserInteraction,
|
||||||
|
style: const TextStyle(color: Colors.black),
|
||||||
|
controller: userController,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: labelText,
|
||||||
|
filled: filled,
|
||||||
|
fillColor: fillColor,
|
||||||
|
),
|
||||||
|
keyboardType: keyboardType,
|
||||||
|
validator: validator,
|
||||||
|
obscureText: labelText == 'Password' ? true : false,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user