Skip to content

Commit 8f5e35e

Browse files
sign up ui
1 parent 9ae33b5 commit 8f5e35e

File tree

5 files changed

+266
-30
lines changed

5 files changed

+266
-30
lines changed

lib/datasource/app_data_source.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import '../utils/helper_functions.dart';
1616
import 'data_source.dart';
1717

1818
class AppDataSource extends DataSource {
19-
final String baseUrl = 'http://192.168.0.104:8080/api/';
19+
final String baseUrl = 'http://192.168.0.110:8080/api/';
2020

2121
Map<String, String> get header => {'Content-Type': 'application/json'};
2222

lib/main.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import 'package:bus_reservation/pages/add_schedule_page.dart';
2+
import 'package:bus_reservation/pages/sign_up_page.dart';
23
import 'package:flutter_easyloading/flutter_easyloading.dart';
34
import 'package:bus_reservation/pages/add_bus_page.dart';
45
import 'package:bus_reservation/pages/add_route_page.dart';
@@ -11,7 +12,6 @@ import 'package:bus_reservation/pages/search_result_page.dart';
1112
import 'package:bus_reservation/pages/seat_plan_page.dart';
1213
import 'package:bus_reservation/utils/constants.dart';
1314
import 'package:flutter/material.dart';
14-
import 'package:go_router/go_router.dart';
1515
import 'package:provider/provider.dart';
1616

1717
import 'pages/add_city.dart';
@@ -50,6 +50,7 @@ class MyApp extends StatelessWidget {
5050
routeNameReservationPage : (context) => const ReservationPage(),
5151
routeNameLoginPage : (context) => const LoginPage(),
5252
routeNameAddCityPage : (context) => const AddCity(),
53+
routeNameSignUpPage : (context) => const SignUpPage(),
5354
},
5455
);
5556
}

lib/pages/login_page.dart

Lines changed: 52 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1+
import 'package:bus_reservation/utils/constants.dart';
12
import 'package:flutter/material.dart';
23
import 'package:provider/provider.dart';
34

45
import '../models/app_user.dart';
56
import '../providers/app_data_provider.dart';
67
import '../utils/helper_functions.dart';
8+
import 'sign_up_page.dart'; // Import the Sign Up page
79

810
class LoginPage extends StatefulWidget {
911
const LoginPage({Key? key}) : super(key: key);
@@ -33,19 +35,23 @@ class _LoginPageState extends State<LoginPage> {
3335
children: [
3436
Padding(
3537
padding: const EdgeInsets.all(32.0),
36-
child: Text('Admin Login', textAlign: TextAlign.center, style: Theme.of(context).textTheme.headlineMedium,),
38+
child: Text(
39+
'Admin Login',
40+
textAlign: TextAlign.center,
41+
style: Theme.of(context).textTheme.headlineMedium,
42+
),
3743
),
3844
Padding(
3945
padding: const EdgeInsets.all(4.0),
4046
child: TextFormField(
4147
controller: _userNameController,
4248
decoration: const InputDecoration(
43-
prefixIcon: Icon(Icons.person_2_outlined),
44-
filled: true,
45-
labelText: 'Username'
49+
prefixIcon: Icon(Icons.person_2_outlined),
50+
filled: true,
51+
labelText: 'Username',
4652
),
4753
validator: (value) {
48-
if(value == null || value.isEmpty) {
54+
if (value == null || value.isEmpty) {
4955
return 'This field must not be empty';
5056
}
5157
return null;
@@ -58,37 +64,55 @@ class _LoginPageState extends State<LoginPage> {
5864
obscureText: isObscure,
5965
controller: _passwordController,
6066
decoration: InputDecoration(
61-
prefixIcon: const Icon(Icons.lock),
62-
filled: true,
63-
labelText: 'Password',
64-
suffixIcon: IconButton(
65-
onPressed: () {
66-
setState(() {
67-
isObscure = !isObscure;
68-
});
69-
},
70-
icon: Icon(isObscure ? Icons.visibility_off : Icons.visibility),
71-
)
67+
prefixIcon: const Icon(Icons.lock),
68+
filled: true,
69+
labelText: 'Password',
70+
suffixIcon: IconButton(
71+
onPressed: () {
72+
setState(() {
73+
isObscure = !isObscure;
74+
});
75+
},
76+
icon: Icon(isObscure ? Icons.visibility_off : Icons.visibility),
77+
),
7278
),
7379
validator: (value) {
74-
if(value == null || value.isEmpty) {
80+
if (value == null || value.isEmpty) {
7581
return 'This field must not be empty';
7682
}
7783
return null;
7884
},
7985
),
8086
),
81-
const SizedBox(height: 20,),
87+
const SizedBox(height: 20),
8288
Center(
83-
child: SizedBox(
84-
width: 100,
85-
height: 50,
86-
child: ElevatedButton(
87-
onPressed: _login,
88-
child: const Text('Login'),
89-
),
89+
child: Column(
90+
children: [
91+
SizedBox(
92+
width: 100,
93+
height: 50,
94+
child: ElevatedButton(
95+
onPressed: _login,
96+
child: const Text('Login'),
97+
),
98+
),
99+
const SizedBox(height: 20),
100+
TextButton(
101+
onPressed: () {
102+
// Navigator.push(
103+
// context,
104+
// MaterialPageRoute(builder: (context) => const SignUpPage()),
105+
// );
106+
Navigator.pushNamed(context, routeNameSignUpPage);
107+
},
108+
child: const Text(
109+
'Don\'t have an account? Sign Up',
110+
style: TextStyle(color: Colors.white70),
111+
),
112+
),
113+
],
90114
),
91-
)
115+
),
92116
],
93117
),
94118
),
@@ -97,12 +121,12 @@ class _LoginPageState extends State<LoginPage> {
97121
}
98122

99123
void _login() async {
100-
if(_formKey.currentState!.validate()) {
124+
if (_formKey.currentState!.validate()) {
101125
final userName = _userNameController.text;
102126
final password = _passwordController.text;
103127
final response = await Provider.of<AppDataProvider>(context, listen: false)
104128
.login(AppUser(userName: userName, password: password));
105-
if(response != null) {
129+
if (response != null) {
106130
showMsg(context, response.message);
107131
Navigator.pop(context);
108132
} else {

lib/pages/sign_up_page.dart

Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
import 'package:flutter/material.dart';
2+
3+
class SignUpPage extends StatefulWidget {
4+
const SignUpPage({Key? key}) : super(key: key);
5+
6+
@override
7+
State<SignUpPage> createState() => _SignUpPageState();
8+
}
9+
10+
class _SignUpPageState extends State<SignUpPage> {
11+
final _formKey = GlobalKey<FormState>();
12+
bool isObscure = true;
13+
14+
final _userNameController = TextEditingController();
15+
final _passwordController = TextEditingController();
16+
final _roleController = TextEditingController();
17+
final _customerNameController = TextEditingController();
18+
final _emailController = TextEditingController();
19+
final _mobileController = TextEditingController();
20+
21+
// FocusNodes to control field navigation
22+
final _userNameFocusNode = FocusNode();
23+
final _passwordFocusNode = FocusNode();
24+
final _customerNameFocusNode = FocusNode();
25+
final _emailFocusNode = FocusNode();
26+
final _mobileFocusNode = FocusNode();
27+
28+
@override
29+
void initState() {
30+
super.initState();
31+
_roleController.text = 'user'; // Default role
32+
}
33+
34+
@override
35+
void dispose() {
36+
// Dispose controllers and focus nodes to free resources
37+
_userNameController.dispose();
38+
_passwordController.dispose();
39+
_roleController.dispose();
40+
_customerNameController.dispose();
41+
_emailController.dispose();
42+
_mobileController.dispose();
43+
_userNameFocusNode.dispose();
44+
_passwordFocusNode.dispose();
45+
_customerNameFocusNode.dispose();
46+
_emailFocusNode.dispose();
47+
_mobileFocusNode.dispose();
48+
super.dispose();
49+
}
50+
51+
@override
52+
Widget build(BuildContext context) {
53+
return Scaffold(
54+
appBar: AppBar(
55+
title: const Text('Sign Up'),
56+
),
57+
body: Form(
58+
key: _formKey,
59+
child: Center(
60+
child: ListView(
61+
padding: const EdgeInsets.symmetric(horizontal: 40, vertical: 8),
62+
shrinkWrap: true,
63+
children: [
64+
Padding(
65+
padding: const EdgeInsets.all(32.0),
66+
child: Text(
67+
'Create Account',
68+
textAlign: TextAlign.center,
69+
style: Theme.of(context).textTheme.headlineMedium,
70+
),
71+
),
72+
_buildTextField(
73+
controller: _userNameController,
74+
label: 'Username',
75+
icon: Icons.person_2_outlined,
76+
focusNode: _userNameFocusNode,
77+
nextFocusNode: _passwordFocusNode,
78+
),
79+
_buildTextField(
80+
controller: _passwordController,
81+
label: 'Password',
82+
icon: Icons.lock,
83+
obscureText: isObscure,
84+
isPassword: true,
85+
focusNode: _passwordFocusNode,
86+
nextFocusNode: _customerNameFocusNode,
87+
),
88+
_buildTextField(
89+
controller: _roleController,
90+
label: 'Role',
91+
icon: Icons.group,
92+
readOnly: true,
93+
),
94+
_buildTextField(
95+
controller: _customerNameController,
96+
label: 'Customer Name',
97+
icon: Icons.person_outline,
98+
focusNode: _customerNameFocusNode,
99+
nextFocusNode: _emailFocusNode,
100+
),
101+
_buildTextField(
102+
controller: _emailController,
103+
label: 'Email',
104+
icon: Icons.email_outlined,
105+
keyboardType: TextInputType.emailAddress,
106+
focusNode: _emailFocusNode,
107+
nextFocusNode: _mobileFocusNode,
108+
),
109+
_buildTextField(
110+
controller: _mobileController,
111+
label: 'Mobile',
112+
icon: Icons.phone_android,
113+
keyboardType: TextInputType.phone,
114+
focusNode: _mobileFocusNode,
115+
textInputAction: TextInputAction.done,
116+
onEditingComplete: () => FocusScope.of(context).unfocus(), // Dismiss keyboard on done
117+
),
118+
const SizedBox(height: 20),
119+
Center(
120+
child: SizedBox(
121+
width: 100,
122+
height: 50,
123+
child: ElevatedButton(
124+
onPressed: _signUp,
125+
child: const Text('Sign Up'),
126+
),
127+
),
128+
),
129+
],
130+
),
131+
),
132+
),
133+
);
134+
}
135+
136+
Widget _buildTextField({
137+
required TextEditingController controller,
138+
required String label,
139+
required IconData icon,
140+
TextInputType keyboardType = TextInputType.text,
141+
bool obscureText = false,
142+
bool isPassword = false,
143+
bool readOnly = false,
144+
FocusNode? focusNode,
145+
FocusNode? nextFocusNode,
146+
TextInputAction textInputAction = TextInputAction.next,
147+
VoidCallback? onEditingComplete,
148+
}) {
149+
return Padding(
150+
padding: const EdgeInsets.all(4.0),
151+
child: TextFormField(
152+
controller: controller,
153+
decoration: InputDecoration(
154+
prefixIcon: Icon(icon),
155+
filled: true,
156+
labelText: label,
157+
suffixIcon: isPassword
158+
? IconButton(
159+
icon: Icon(obscureText ? Icons.visibility_off : Icons.visibility),
160+
onPressed: () {
161+
setState(() {
162+
isObscure = !isObscure;
163+
});
164+
},
165+
)
166+
: null,
167+
),
168+
keyboardType: keyboardType,
169+
obscureText: obscureText,
170+
readOnly: readOnly,
171+
focusNode: focusNode,
172+
textInputAction: textInputAction,
173+
onEditingComplete: onEditingComplete ??
174+
() {
175+
if (nextFocusNode != null) {
176+
FocusScope.of(context).requestFocus(nextFocusNode);
177+
}
178+
},
179+
validator: (value) {
180+
if (value == null || value.isEmpty) {
181+
return 'This field must not be empty';
182+
}
183+
return null;
184+
},
185+
),
186+
);
187+
}
188+
189+
void _signUp() {
190+
if (_formKey.currentState!.validate()) {
191+
final userData = {
192+
"userName": _userNameController.text,
193+
"password": _passwordController.text,
194+
"role": _roleController.text,
195+
"customer_name": _customerNameController.text,
196+
"email": _emailController.text,
197+
"mobile": _mobileController.text,
198+
};
199+
200+
// Implement sign-up logic here
201+
print('User Data: $userData');
202+
203+
// Show success message and navigate back or to another screen
204+
ScaffoldMessenger.of(context).showSnackBar(
205+
const SnackBar(content: Text('Sign up successful')),
206+
);
207+
Navigator.pop(context);
208+
}
209+
}
210+
}

lib/utils/constants.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ const String routeNameAddSchedulePage = 'add_schedule';
2323
const String routeNameScheduleListPage = 'schedule_list';
2424
const String routeNameReservationPage = 'reservation';
2525
const String routeNameAddCityPage = 'add_city';
26+
const String routeNameSignUpPage = 'sign_up';
2627
const String unknownErrMessage = 'Unknown error!';
2728

2829

0 commit comments

Comments
 (0)