Signup screen and functionality
This commit is contained in:
1 parent
08f0668997
commit
c3e55e89f2
6 files changed
+155
-11
No files matched your search
@@ -7,6 +7,8 @@ class ConfigField {
|
||||
final String name;
|
||||
final String type;
|
||||
final TextEditingController controller;
|
||||
// There should be an additional property to indicate whether this field is deactivated/removed/reset
|
||||
// meaning it will be set as 'null' (default) rather than any string, otherwise only an empty string can be set
|
||||
|
||||
ConfigField({required this.name, required this.type, required this.controller});
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'dart:html';
|
||||
import 'dart:convert';
|
||||
import 'dart:async'; // Import for handling Completers
|
||||
import 'dart:async';
|
||||
|
||||
class ChatInfo {
|
||||
int id;
|
||||
@@ -31,6 +32,23 @@ class Backend {
|
||||
connect();
|
||||
}
|
||||
|
||||
static Future<void> signup(String username, String email, String password) async {
|
||||
final response = await http.post(Uri.parse("$_url/user/signup"),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: jsonEncode({
|
||||
'username': username,
|
||||
'email': email,
|
||||
'password': password,
|
||||
})
|
||||
);
|
||||
|
||||
if (response.statusCode < 200 || response.statusCode >= 300) {
|
||||
throw Exception("Signup Status Code ${response.statusCode}");
|
||||
}
|
||||
}
|
||||
|
||||
static Future<void> auth(String username, String password) {
|
||||
_socket!.send(json.encode({'username': username, 'password': password}));
|
||||
_credentials = (username: username, password: password);
|
||||
@@ -43,7 +61,7 @@ class Backend {
|
||||
}
|
||||
|
||||
static void connect() {
|
||||
_socket = WebSocket(_url!);
|
||||
_socket = WebSocket(_url! + "/ws");
|
||||
_socket!.onOpen.listen((event) {
|
||||
print('Connected to the WebSocket server');
|
||||
Backend.invalidateCache(chat: true);
|
||||
|
||||
@@ -1,24 +1,52 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'backend.dart';
|
||||
|
||||
class LoginScreen extends StatelessWidget {
|
||||
final Function(String, String) onLogin;
|
||||
final bool isSignupMode; // Changed to a boolean
|
||||
|
||||
LoginScreen({required this.onLogin});
|
||||
LoginScreen({required this.onLogin, this.isSignupMode = false}); // Default to false (login mode)
|
||||
|
||||
final TextEditingController usernameController = TextEditingController();
|
||||
final TextEditingController passwordController = TextEditingController();
|
||||
final TextEditingController emailController = TextEditingController();
|
||||
final TextEditingController confirmPasswordController = TextEditingController();
|
||||
|
||||
final FocusNode usernameFocusNode = FocusNode();
|
||||
final FocusNode passwordFocusNode = FocusNode();
|
||||
final FocusNode emailFocusNode = FocusNode();
|
||||
final FocusNode confirmPasswordFocusNode = FocusNode();
|
||||
|
||||
void _handleLogin() {
|
||||
onLogin(usernameController.text, passwordController.text);
|
||||
}
|
||||
|
||||
void _handleSignup(BuildContext context) async {
|
||||
final username = usernameController.text;
|
||||
final password = passwordController.text;
|
||||
final email = emailController.text;
|
||||
|
||||
if (password != confirmPasswordController.text) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text("Passwords don't match")),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await Backend.signup(username, email, password);
|
||||
_handleLogin();
|
||||
} catch (e) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text('Could not signup: $e')),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: Text('Login')),
|
||||
appBar: AppBar(title: Text(isSignupMode ? 'Signup' : 'Login')), // Dynamic title
|
||||
body: Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
@@ -31,24 +59,87 @@ class LoginScreen extends StatelessWidget {
|
||||
decoration: InputDecoration(labelText: 'Username'),
|
||||
textInputAction: TextInputAction.next,
|
||||
onSubmitted: (_) {
|
||||
FocusScope.of(context).requestFocus(passwordFocusNode);
|
||||
if (!isSignupMode) { // If not in signup mode, move to password
|
||||
FocusScope.of(context).requestFocus(passwordFocusNode);
|
||||
} else { // In signup mode, move to email
|
||||
FocusScope.of(context).requestFocus(emailFocusNode);
|
||||
}
|
||||
},
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
if (isSignupMode) ...[ // Conditionally show email field
|
||||
TextField(
|
||||
controller: emailController,
|
||||
focusNode: emailFocusNode,
|
||||
decoration: InputDecoration(labelText: 'Email'),
|
||||
keyboardType: TextInputType.emailAddress,
|
||||
textInputAction: TextInputAction.next,
|
||||
onSubmitted: (_) {
|
||||
FocusScope.of(context).requestFocus(passwordFocusNode);
|
||||
},
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
],
|
||||
TextField(
|
||||
controller: passwordController,
|
||||
focusNode: passwordFocusNode,
|
||||
decoration: InputDecoration(labelText: 'Password'),
|
||||
obscureText: true,
|
||||
textInputAction: TextInputAction.done,
|
||||
textInputAction: isSignupMode ? TextInputAction.next : TextInputAction.done, // Adjust text action
|
||||
onSubmitted: (_) {
|
||||
_handleLogin();
|
||||
if (!isSignupMode) { // If not in signup mode, handle login
|
||||
_handleLogin();
|
||||
} else { // In signup mode, move to confirm password
|
||||
FocusScope.of(context).requestFocus(confirmPasswordFocusNode);
|
||||
}
|
||||
},
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
if (isSignupMode) ...[ // Conditionally show confirm password field
|
||||
TextField(
|
||||
controller: confirmPasswordController,
|
||||
focusNode: confirmPasswordFocusNode,
|
||||
decoration: InputDecoration(labelText: 'Confirm Password'),
|
||||
obscureText: true,
|
||||
textInputAction: TextInputAction.done,
|
||||
onSubmitted: (_) {
|
||||
_handleSignup(context);
|
||||
},
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
],
|
||||
ElevatedButton(
|
||||
onPressed: _handleLogin,
|
||||
child: Text('Login'),
|
||||
onPressed: () {
|
||||
if (!isSignupMode) { // If not in signup mode, handle login
|
||||
_handleLogin();
|
||||
} else { // In signup mode, handle signup
|
||||
_handleSignup(context);
|
||||
}
|
||||
},
|
||||
child: Text(isSignupMode ? 'Signup' : 'Login'), // Dynamic button text
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
if (!isSignupMode) { // If in login mode, navigate to signup
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (context) => LoginScreen(
|
||||
onLogin: onLogin,
|
||||
isSignupMode: true, // Push with signup mode
|
||||
),
|
||||
),
|
||||
);
|
||||
} else { // If in signup mode, pop back to login
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
},
|
||||
child: Text(
|
||||
isSignupMode
|
||||
? 'Already have an account? Login' // Text for signup mode
|
||||
: 'Don\'t have an account? Sign Up', // Text for login mode
|
||||
style: TextStyle(color: Colors.blue),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -56,4 +147,4 @@ class LoginScreen extends StatelessWidget {
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,7 @@ void main() {
|
||||
print("Main");
|
||||
Config.loadConfig(); // Load the configuration before running the app
|
||||
|
||||
Backend.setup('${Config.backendUrl}/ws');
|
||||
Backend.setup(Config.backendUrl!);
|
||||
runApp(HubApp());
|
||||
}
|
||||
|
||||
|
||||
@@ -136,6 +136,22 @@ packages:
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
http:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: http
|
||||
sha256: "2c11f3f94c687ee9bad77c171151672986360b2b001d109814ee7140b2cf261b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.4.0"
|
||||
http_parser:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: http_parser
|
||||
sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.1.2"
|
||||
js:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -325,6 +341,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.4"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: typed_data
|
||||
sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.4.0"
|
||||
vector_math:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -341,6 +365,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "14.3.1"
|
||||
web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: web
|
||||
sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
win32:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@@ -37,6 +37,7 @@ dependencies:
|
||||
|
||||
# For user credentials and sensitive data
|
||||
flutter_secure_storage: ^9.2.4
|
||||
http: ^1.4.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
||||
Reference in new issue
Block a user