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 name;
|
||||||
final String type;
|
final String type;
|
||||||
final TextEditingController controller;
|
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});
|
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:html';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:async'; // Import for handling Completers
|
import 'dart:async';
|
||||||
|
|
||||||
class ChatInfo {
|
class ChatInfo {
|
||||||
int id;
|
int id;
|
||||||
@@ -31,6 +32,23 @@ class Backend {
|
|||||||
connect();
|
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) {
|
static Future<void> auth(String username, String password) {
|
||||||
_socket!.send(json.encode({'username': username, 'password': password}));
|
_socket!.send(json.encode({'username': username, 'password': password}));
|
||||||
_credentials = (username: username, password: password);
|
_credentials = (username: username, password: password);
|
||||||
@@ -43,7 +61,7 @@ class Backend {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void connect() {
|
static void connect() {
|
||||||
_socket = WebSocket(_url!);
|
_socket = WebSocket(_url! + "/ws");
|
||||||
_socket!.onOpen.listen((event) {
|
_socket!.onOpen.listen((event) {
|
||||||
print('Connected to the WebSocket server');
|
print('Connected to the WebSocket server');
|
||||||
Backend.invalidateCache(chat: true);
|
Backend.invalidateCache(chat: true);
|
||||||
|
|||||||
@@ -1,24 +1,52 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'backend.dart';
|
||||||
|
|
||||||
class LoginScreen extends StatelessWidget {
|
class LoginScreen extends StatelessWidget {
|
||||||
final Function(String, String) onLogin;
|
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 usernameController = TextEditingController();
|
||||||
final TextEditingController passwordController = TextEditingController();
|
final TextEditingController passwordController = TextEditingController();
|
||||||
|
final TextEditingController emailController = TextEditingController();
|
||||||
|
final TextEditingController confirmPasswordController = TextEditingController();
|
||||||
|
|
||||||
final FocusNode usernameFocusNode = FocusNode();
|
final FocusNode usernameFocusNode = FocusNode();
|
||||||
final FocusNode passwordFocusNode = FocusNode();
|
final FocusNode passwordFocusNode = FocusNode();
|
||||||
|
final FocusNode emailFocusNode = FocusNode();
|
||||||
|
final FocusNode confirmPasswordFocusNode = FocusNode();
|
||||||
|
|
||||||
void _handleLogin() {
|
void _handleLogin() {
|
||||||
onLogin(usernameController.text, passwordController.text);
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(title: Text('Login')),
|
appBar: AppBar(title: Text(isSignupMode ? 'Signup' : 'Login')), // Dynamic title
|
||||||
body: Center(
|
body: Center(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(16.0),
|
padding: const EdgeInsets.all(16.0),
|
||||||
@@ -31,24 +59,87 @@ class LoginScreen extends StatelessWidget {
|
|||||||
decoration: InputDecoration(labelText: 'Username'),
|
decoration: InputDecoration(labelText: 'Username'),
|
||||||
textInputAction: TextInputAction.next,
|
textInputAction: TextInputAction.next,
|
||||||
onSubmitted: (_) {
|
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),
|
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(
|
TextField(
|
||||||
controller: passwordController,
|
controller: passwordController,
|
||||||
focusNode: passwordFocusNode,
|
focusNode: passwordFocusNode,
|
||||||
decoration: InputDecoration(labelText: 'Password'),
|
decoration: InputDecoration(labelText: 'Password'),
|
||||||
obscureText: true,
|
obscureText: true,
|
||||||
textInputAction: TextInputAction.done,
|
textInputAction: isSignupMode ? TextInputAction.next : TextInputAction.done, // Adjust text action
|
||||||
onSubmitted: (_) {
|
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),
|
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(
|
ElevatedButton(
|
||||||
onPressed: _handleLogin,
|
onPressed: () {
|
||||||
child: Text('Login'),
|
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");
|
print("Main");
|
||||||
Config.loadConfig(); // Load the configuration before running the app
|
Config.loadConfig(); // Load the configuration before running the app
|
||||||
|
|
||||||
Backend.setup('${Config.backendUrl}/ws');
|
Backend.setup(Config.backendUrl!);
|
||||||
runApp(HubApp());
|
runApp(HubApp());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -136,6 +136,22 @@ packages:
|
|||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
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:
|
js:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -325,6 +341,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.4"
|
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:
|
vector_math:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -341,6 +365,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "14.3.1"
|
version: "14.3.1"
|
||||||
|
web:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: web
|
||||||
|
sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.1"
|
||||||
win32:
|
win32:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ dependencies:
|
|||||||
|
|
||||||
# For user credentials and sensitive data
|
# For user credentials and sensitive data
|
||||||
flutter_secure_storage: ^9.2.4
|
flutter_secure_storage: ^9.2.4
|
||||||
|
http: ^1.4.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|||||||
Reference in new issue
Block a user