log in and register mock

This commit is contained in:
Mikkel Troels Kongsted 2025-02-07 09:54:27 +01:00
parent f4886e045c
commit caa33d0a7d
7 changed files with 273 additions and 49 deletions

View File

@ -5,6 +5,7 @@ import 'package:mobile/repos/location_image.dart';
import 'package:mobile/repos/paying_state.dart'; import 'package:mobile/repos/paying_state.dart';
import 'package:mobile/repos/product.dart'; import 'package:mobile/repos/product.dart';
import 'package:mobile/repos/receipt.dart'; import 'package:mobile/repos/receipt.dart';
import 'package:mobile/repos/user.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'pages/landing_page.dart'; import 'pages/landing_page.dart';
import 'package:mobile/repos/bottom_navigation_bar.dart'; import 'package:mobile/repos/bottom_navigation_bar.dart';
@ -27,6 +28,7 @@ class MyApp extends StatelessWidget {
ChangeNotifierProvider(create: (_) => PayingStateRepo()), ChangeNotifierProvider(create: (_) => PayingStateRepo()),
ChangeNotifierProvider(create: (_) => AddToCartStateRepo()), ChangeNotifierProvider(create: (_) => AddToCartStateRepo()),
ChangeNotifierProvider(create: (_) => LocationImageRepo()), ChangeNotifierProvider(create: (_) => LocationImageRepo()),
ChangeNotifierProvider(create: (_) => UsersRepo()),
], ],
child: MaterialApp( child: MaterialApp(
title: 'Fresh Plaza', title: 'Fresh Plaza',

View File

@ -1,6 +1,10 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:mobile/repos/user.dart';
import 'package:mobile/results.dart';
import 'package:mobile/widgets/error_box.dart';
import 'package:mobile/widgets/primary_button.dart'; import 'package:mobile/widgets/primary_button.dart';
import 'package:mobile/widgets/primary_input.dart'; import 'package:mobile/widgets/primary_input.dart';
import 'package:provider/provider.dart';
import 'dashboard.dart'; import 'dashboard.dart';
class LogInPage extends StatelessWidget { class LogInPage extends StatelessWidget {
@ -8,27 +12,68 @@ class LogInPage extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return const Scaffold(
body: Row(mainAxisAlignment: MainAxisAlignment.center, children: [ body: Row(
Column( mainAxisAlignment: MainAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center, children: [LogInForm()]));
children: [ }
Text( }
"Log ind",
style: Theme.of(context).textTheme.headlineLarge, class LogInForm extends StatefulWidget {
), const LogInForm({super.key});
const PrimaryInput(
label: "Mail/Tlf", placeholderText: "f.eks. example@example.com"), @override
const PrimaryInput( State<StatefulWidget> createState() => LogInFormState();
label: "Password", placeholderText: "*********", obscure: true), }
PrimaryButton(
onPressed: () => { class LogInFormState extends State<LogInForm> {
Navigator.of(context).push( bool loginError = false;
MaterialPageRoute(builder: (context) => Dashboard())) @override
}, Widget build(BuildContext context) {
child: const Text("Log ind")) final mailController = TextEditingController();
], final passwordController = TextEditingController();
)
])); return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Log ind",
style: Theme.of(context).textTheme.headlineLarge,
),
ErrorBox(
visible: loginError,
errorText: "Ugyldig mail eller password",
onClosePressed: () {
setState(() => loginError = false);
},
),
PrimaryInput(
label: "Mail/Tlf",
placeholderText: "f.eks. example@example.com",
controller: mailController,
),
PrimaryInput(
label: "Password",
placeholderText: "*********",
obscure: true,
controller: passwordController,
),
PrimaryButton(
onPressed: () {
final usersRepo = context.read<UsersRepo>();
final loginResult =
usersRepo.login(mailController.text, passwordController.text);
if (loginResult is Ok) {
Navigator.of(context)
.push(MaterialPageRoute(builder: (context) => Dashboard()));
} else {
setState(() {
loginError = true;
});
}
},
child: const Text("Log ind"))
],
);
} }
} }

View File

@ -1,6 +1,10 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:mobile/repos/user.dart';
import 'package:mobile/results.dart';
import 'package:mobile/widgets/error_box.dart';
import 'package:mobile/widgets/primary_button.dart'; import 'package:mobile/widgets/primary_button.dart';
import 'package:mobile/widgets/primary_input.dart'; import 'package:mobile/widgets/primary_input.dart';
import 'package:provider/provider.dart';
import 'log_in_page.dart'; import 'log_in_page.dart';
class RegisterPage extends StatelessWidget { class RegisterPage extends StatelessWidget {
@ -8,32 +12,78 @@ class RegisterPage extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return const Scaffold(
body: Row(mainAxisAlignment: MainAxisAlignment.center, children: [ body: Row(
Column( mainAxisAlignment: MainAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center, children: [RegisterForm()]));
children: [ }
Text( }
"Opret bruger",
style: Theme.of(context).textTheme.headlineLarge, class RegisterForm extends StatefulWidget {
), const RegisterForm({super.key});
const PrimaryInput(label: "Fornavn", placeholderText: "Fornavn"),
const PrimaryInput( @override
label: "Mail/Tlf", placeholderText: "f.eks. example@example.com"), State<StatefulWidget> createState() => RegisterFormState();
const PrimaryInput( }
label: "Password", placeholderText: "*********", obscure: true),
const PrimaryInput( class RegisterFormState extends State<RegisterForm> {
label: "Password (igen)", bool registerError = false;
placeholderText: "*********",
obscure: true), @override
PrimaryButton( Widget build(BuildContext context) {
onPressed: () => { final nameController = TextEditingController();
Navigator.of(context).push(MaterialPageRoute( final mailController = TextEditingController();
builder: (context) => const LogInPage())) final passwordController = TextEditingController();
}, return Column(
child: const Text("Opret bruger")) mainAxisAlignment: MainAxisAlignment.center,
], children: [
) Text(
])); "Opret bruger",
style: Theme.of(context).textTheme.headlineLarge,
),
ErrorBox(
visible: registerError,
errorText: "Bruger med mailen ${mailController.text}",
onClosePressed: () {
setState(() {
registerError = false;
});
}),
PrimaryInput(
label: "Fornavn",
placeholderText: "Fornavn",
controller: nameController,
),
PrimaryInput(
label: "Mail/Tlf",
placeholderText: "f.eks. example@example.com",
controller: mailController,
),
PrimaryInput(
label: "Password",
placeholderText: "*********",
obscure: true,
controller: passwordController,
),
const PrimaryInput(
label: "Password (igen)",
placeholderText: "*********",
obscure: true),
PrimaryButton(
onPressed: () {
final usersRepo = context.read<UsersRepo>();
if (usersRepo.addUser(nameController.text, mailController.text,
passwordController.text) is Ok) {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => const LogInPage()));
} else {
setState(() {
registerError = true;
});
}
},
child: const Text("Opret bruger"))
],
);
} }
} }

View File

@ -0,0 +1,73 @@
import 'package:flutter/material.dart';
import 'package:mobile/results.dart';
class UsersRepo extends ChangeNotifier {
int nextId = 0;
final List<User> users = [];
UsersRepo() {
addTestUsers();
}
Result<User, String> getUserById(int id) {
for (var i = 0; i < users.length; i++) {
if (users[i].id == id) {
return Ok(users[i]);
}
}
return Err("User with id $id doesn't exist");
}
Result<User, String> getUserByMail(String mail) {
for (var i = 0; i < users.length; i++) {
if (users[i].mail == mail) {
return Ok(users[i]);
}
}
return Err("User with mail $mail doesn't exist");
}
Result<User, String> addUser(String name, String mail, String password) {
if (getUserByMail(mail) is Ok) {
return Err("User with mail $mail already exists");
}
final user = User(id: nextId++, name: name, mail: mail, password: password);
users.add(user);
return Ok(user);
}
Result<User, String> login(String mail, String password) {
for (var i = 0; i < users.length; i++) {
if (users[i].mail != mail) {
continue;
}
if (users[i].password == password) {
return Ok(users[i]);
}
return Err("Wrong password for user with mail $mail");
}
return Err("User with mail $mail doesn't exist");
}
void addTestUsers() {
users
..add(User(
id: nextId++, mail: "test@test.com", name: "test", password: "test"))
..add(User(id: nextId++, mail: "", name: "", password: ""));
}
}
class User {
final int id;
final String mail;
final String name;
final String password;
User(
{required this.id,
required this.mail,
required this.name,
required this.password});
}

13
mobile/lib/results.dart Normal file
View File

@ -0,0 +1,13 @@
sealed class Result<T, E> {}
final class Ok<T, E> implements Result<T, E> {
final T value;
const Ok(this.value);
}
final class Err<T, E> implements Result<T, E> {
final E value;
const Err(this.value);
}

View File

@ -0,0 +1,34 @@
import 'package:flutter/material.dart';
class ErrorBox extends StatelessWidget {
final bool visible;
final void Function() onClosePressed;
final String errorText;
const ErrorBox(
{super.key,
this.visible = true,
required this.errorText,
required this.onClosePressed});
@override
Widget build(BuildContext context) {
return Visibility(
visible: visible,
child: Container(
padding: const EdgeInsets.fromLTRB(10, 10, 0, 10),
margin: const EdgeInsets.all(10),
decoration: BoxDecoration(
border: Border.all(color: const Color.fromARGB(170, 248, 81, 73)),
borderRadius: const BorderRadius.all(Radius.circular(5)),
color: const Color.fromARGB(50, 248, 81, 73),
),
child: Row(
children: [
const Text("Ugyldigt mail eller password"),
IconButton(onPressed: onClosePressed, icon: const Icon(Icons.close))
],
),
),
);
}
}

View File

@ -6,12 +6,16 @@ class PrimaryInput extends StatelessWidget {
final String label; final String label;
final String placeholderText; final String placeholderText;
final bool obscure; final bool obscure;
final String? errorText;
final TextEditingController? controller;
const PrimaryInput( const PrimaryInput(
{super.key, {super.key,
this.width = 300, this.width = 300,
this.height = 100, this.height = 100,
this.obscure = false, this.obscure = false,
this.errorText,
this.controller,
required this.label, required this.label,
required this.placeholderText}); required this.placeholderText});
@override @override
@ -20,8 +24,11 @@ class PrimaryInput extends StatelessWidget {
width: width, width: width,
height: height, height: height,
child: TextField( child: TextField(
controller: controller,
decoration: InputDecoration( decoration: InputDecoration(
border: const OutlineInputBorder(), border: const OutlineInputBorder(),
errorStyle: const TextStyle(),
errorText: errorText,
label: Text(label), label: Text(label),
hintText: placeholderText, hintText: placeholderText,
filled: true, filled: true,