added register screen

This commit is contained in:
doman 2023-07-30 13:42:38 +02:00
parent 6ebd162eda
commit 18bad804b7
3 changed files with 160 additions and 12 deletions

View file

@ -20,8 +20,8 @@ class ApiClient {
} }
} }
Map<String, String> headers({bool forGet = false}) { Map<String, String> headers({bool forGet = false, bool forLogin = false}) {
if (token == null) { if (token == null && !forLogin) {
throw Exception('Not logged in'); throw Exception('Not logged in');
} }
@ -61,11 +61,11 @@ class ApiClient {
return _jsonDecode(response); return _jsonDecode(response);
} }
Future<Map<String, dynamic>> post(String path, Map<String, dynamic> body) async { Future<Map<String, dynamic>> post(String path, Map<String, dynamic> body, {bool forLogin = false}) async {
final response = await httpClient.post( final response = await httpClient.post(
Uri.parse('$baseUrl$path'), Uri.parse('$baseUrl$path'),
body: jsonEncode(body), body: jsonEncode(body),
headers: headers(), headers: headers(forLogin: forLogin),
); );
if (response.statusCode != 200) { if (response.statusCode != 200) {
@ -198,4 +198,17 @@ class ApiClient {
}; };
await patch("/entry/$id", entry); await patch("/entry/$id", entry);
} }
Future<void> register(String username, String password) async {
try {
await post("/user", {
"username": username,
"password": password,
},
forLogin: true,
);
} catch (e) {
throw Exception("Failed to register");
}
}
} }

View file

@ -1,6 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:fooder_web/screens/based.dart'; import 'package:fooder_web/screens/based.dart';
import 'package:fooder_web/screens/main.dart'; import 'package:fooder_web/screens/main.dart';
import 'package:fooder_web/screens/register.dart';
class LoginScreen extends BasedScreen { class LoginScreen extends BasedScreen {
@ -99,24 +100,41 @@ class _LoginScreen extends State<LoginScreen> {
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[ children: <Widget>[
TextFormField( TextFormField(
decoration: const InputDecoration( decoration: const InputDecoration(
labelText: 'Username', labelText: 'Username',
), ),
controller: usernameController, controller: usernameController,
), ),
TextFormField( TextFormField(
obscureText: true, obscureText: true,
decoration: const InputDecoration( decoration: const InputDecoration(
labelText: 'Password', labelText: 'Password',
), ),
controller: passwordController, controller: passwordController,
onFieldSubmitted: (_) => _login() onFieldSubmitted: (_) => _login()
), ),
FilledButton( Padding(
onPressed: _login, padding: const EdgeInsets.symmetric(vertical: 10),
child: const Text('Login'), child: FilledButton(
) onPressed: _login,
child: const Text('Login'),
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: TextButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => RegisterScreen(apiClient: widget.apiClient),
),
);
},
child: const Text('Don\'t have an account? Register here!'),
),
),
], ],
), ),
), ),

117
lib/screens/register.dart Normal file
View file

@ -0,0 +1,117 @@
import 'package:flutter/material.dart';
import 'package:fooder_web/screens/based.dart';
class RegisterScreen extends BasedScreen {
const RegisterScreen({super.key, required super.apiClient});
@override
State<RegisterScreen> createState() => _RegisterScreen();
}
class _RegisterScreen extends State<RegisterScreen> {
final usernameController = TextEditingController();
final passwordController = TextEditingController();
final passwordConfirmController = TextEditingController();
@override
void dispose() {
usernameController.dispose();
passwordController.dispose();
passwordConfirmController.dispose();
super.dispose();
}
void showError(String message)
{
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(message, textAlign: TextAlign.center),
backgroundColor: Theme.of(context).colorScheme.error,
),
);
}
void showText(String text)
{
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(text, textAlign: TextAlign.center),
backgroundColor: Theme.of(context).colorScheme.primary,
),
);
}
void popMeDady() {
Navigator.pop(context);
}
// login client when button pressed
Future<void> _register() async {
if (passwordController.text != passwordConfirmController.text) {
showError("Passwords don't match");
return;
}
try {
await widget.apiClient.register(
usernameController.text,
passwordController.text,
);
showText("Created account. You can now log in.");
popMeDady();
} on Exception catch (e) {
showError(e.toString());
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: const Text("FOODER"),
),
body: Center(
child: Container(
constraints: const BoxConstraints(maxWidth: 600),
padding: const EdgeInsets.all(10),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextFormField(
decoration: const InputDecoration(
labelText: 'Username',
),
controller: usernameController,
),
TextFormField(
obscureText: true,
decoration: const InputDecoration(
labelText: 'Password',
),
controller: passwordController,
),
TextFormField(
obscureText: true,
decoration: const InputDecoration(
labelText: 'Confirm password',
),
controller: passwordConfirmController,
onFieldSubmitted: (_) => _register()
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: FilledButton(
onPressed: _register,
child: const Text('Register'),
)
),
],
),
),
),
);
}
}