diff options
Diffstat (limited to 'mobile/lib')
| -rw-r--r-- | mobile/lib/cart.dart | 95 | ||||
| -rw-r--r-- | mobile/lib/credit_card_payment.dart | 68 | ||||
| -rw-r--r-- | mobile/lib/login.dart | 161 | ||||
| -rw-r--r-- | mobile/lib/main.dart | 200 | ||||
| -rw-r--r-- | mobile/lib/order_history.dart | 181 | ||||
| -rw-r--r-- | mobile/lib/payement_order.dart | 81 | ||||
| -rw-r--r-- | mobile/lib/routes.dart | 99 | ||||
| -rw-r--r-- | mobile/lib/signup.dart | 200 |
8 files changed, 1085 insertions, 0 deletions
diff --git a/mobile/lib/cart.dart b/mobile/lib/cart.dart new file mode 100644 index 0000000..b3d5b0b --- /dev/null +++ b/mobile/lib/cart.dart @@ -0,0 +1,95 @@ +import 'package:flutter/material.dart'; + +// Define a Ride class to represent the selected ride +class Ride { + final String name; + final String startLocation; + final String endLocation; + final String time; + + Ride({ + required this.name, + required this.startLocation, + required this.endLocation, + required this.time, + }); +} + +class CartPage extends StatelessWidget { + final Ride selectedRide; + + CartPage({required this.selectedRide}); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Cart'), + ), + body: Padding( + padding: const EdgeInsets.all(16.0), + child: Card( + elevation: 5, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: <Widget>[ + const Text( + 'Selected Ride:', + style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + ), + const SizedBox(height: 12), + ListTile( + leading: const Icon(Icons.directions_car, color: Colors.blue), + title: Text(selectedRide.name), + subtitle: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 8), + Row( + children: [ + const Icon(Icons.location_on, color: Colors.blue), + const SizedBox(width: 4), + Text(selectedRide.startLocation), + ], + ), + const SizedBox(height: 4), + Row( + children: [ + const Icon(Icons.arrow_forward, color: Colors.blue), + const SizedBox(width: 4), + Text(selectedRide.endLocation), + ], + ), + const SizedBox(height: 4), + Row( + children: [ + const Icon(Icons.access_time, color: Colors.blue), + const SizedBox(width: 4), + Text(selectedRide.time), + ], + ), + ], + ), + ), + const SizedBox(height: 20), + ElevatedButton( + onPressed: () { + // Implement payment or confirmation logic here + // For now, just print a message + print('Processing payment/confirmation...'); + }, + child: const Text('Proceed to Payment/Confirm'), + ), + ], + ), + ), + ), + ), + ); + } +} diff --git a/mobile/lib/credit_card_payment.dart b/mobile/lib/credit_card_payment.dart new file mode 100644 index 0000000..ef1d737 --- /dev/null +++ b/mobile/lib/credit_card_payment.dart @@ -0,0 +1,68 @@ +import 'package:flutter/material.dart'; + +class CreditCardDetailsPage extends StatelessWidget { + final String orderID; + + CreditCardDetailsPage({required this.orderID}); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Credit Card Details'), + ), + body: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + const Icon( + Icons.credit_card, + size: 100, + color: Colors.blue, + ), + const SizedBox(height: 24.0), + TextFormField( + decoration: const InputDecoration( + labelText: 'Card Number', + hintText: 'Enter your card number', + prefixIcon: Icon(Icons.payment), + ), + keyboardType: TextInputType.number, + ), + const SizedBox(height: 16.0), + TextFormField( + decoration: const InputDecoration( + labelText: 'Expiration Date', + hintText: 'MM/YYYY', + prefixIcon: Icon(Icons.date_range), + ), + keyboardType: TextInputType.datetime, + ), + const SizedBox(height: 16.0), + TextFormField( + decoration: const InputDecoration( + labelText: 'CVV', + hintText: 'Enter CVV', + prefixIcon: Icon(Icons.lock), + ), + keyboardType: TextInputType.number, + obscureText: true, + ), + const SizedBox(height: 24.0), + ElevatedButton( + onPressed: () { + // TODO: + // Implement payment processing logic here + print('Payment processed for Order ID: $orderID'); + Navigator.pop( + context); // Return to previous screen after payment + }, + child: const Text('Submit Payment'), + ), + ], + ), + ), + ); + } +} diff --git a/mobile/lib/login.dart b/mobile/lib/login.dart new file mode 100644 index 0000000..b210650 --- /dev/null +++ b/mobile/lib/login.dart @@ -0,0 +1,161 @@ +import 'package:flutter/material.dart'; +import 'package:fluttertoast/fluttertoast.dart'; +import 'package:firebase_auth/firebase_auth.dart'; + +class LoginPage extends StatefulWidget { + const LoginPage({ + Key? key, + }) : super(key: key); + + @override + State<LoginPage> createState() => _LoginPageState(); +} + +class _LoginPageState extends State<LoginPage> { + final GlobalKey<FormState> _formKey = GlobalKey(); + + final FocusNode _focusNodePassword = FocusNode(); + final TextEditingController _controllerUsername = TextEditingController(); + final TextEditingController _controllerPassword = TextEditingController(); + + bool _obscurePassword = true; + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.grey[300], + body: Form( + key: _formKey, + child: SingleChildScrollView( + padding: const EdgeInsets.all(30.0), + child: Column( + children: [ + Image.asset( + "assets/logo.png", + height: 190, + ), + Text( + "Welcome back", + style: Theme.of(context).textTheme.headlineMedium, + ), + Text( + "Login to your account", + style: Theme.of(context).textTheme.bodySmall, + ), + const SizedBox(height: 40), + TextFormField( + controller: _controllerUsername, + keyboardType: TextInputType.name, + decoration: InputDecoration( + labelText: "Email", + prefixIcon: const Icon(Icons.email_outlined), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(10), + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(10), + ), + ), + onEditingComplete: () => _focusNodePassword.requestFocus(), + validator: (String? value) { + if (value == null || value.isEmpty) { + return "Please enter username."; + } + + return null; + }, + ), + const SizedBox(height: 10), + TextFormField( + controller: _controllerPassword, + focusNode: _focusNodePassword, + obscureText: _obscurePassword, + keyboardType: TextInputType.visiblePassword, + decoration: InputDecoration( + labelText: "Password", + prefixIcon: const Icon(Icons.password_outlined), + suffixIcon: IconButton( + onPressed: () { + setState(() { + _obscurePassword = !_obscurePassword; + }); + }, + icon: _obscurePassword + ? const Icon(Icons.visibility_outlined) + : const Icon(Icons.visibility_off_outlined)), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(10), + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(10), + ), + ), + validator: (String? value) { + if (value == null || value.isEmpty) { + return "Please enter password."; + } + + return null; + }, + ), + const SizedBox(height: 60), + Column( + children: [ + ElevatedButton( + style: ElevatedButton.styleFrom( + minimumSize: const Size.fromHeight(50), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(20), + ), + backgroundColor: Color(0xFF355291), + ), + onPressed: () async { + if (_formKey.currentState?.validate() ?? false) { + try { + await FirebaseAuth.instance + .signInWithEmailAndPassword( + email: _controllerUsername.text.trim(), + password: _controllerPassword.text.trim()) + .then((value) => + Navigator.pushNamedAndRemoveUntil( + context, '/', (route) => false)); + } on FirebaseAuthException catch (e) { + Fluttertoast.showToast( + msg: e.message.toString(), + gravity: ToastGravity.SNACKBAR); + } + } + }, + child: const Text("Login"), + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text("Don't have an account?"), + TextButton( + onPressed: () { + _formKey.currentState?.reset(); + Navigator.pushNamedAndRemoveUntil( + context, "/signup", (route) => false); + }, + child: const Text("Signup"), + ), + ], + ), + ], + ), + ], + ), + ), + ), + ); + } + + @override + void dispose() { + _focusNodePassword.dispose(); + _controllerUsername.dispose(); + _controllerPassword.dispose(); + super.dispose(); + } +} diff --git a/mobile/lib/main.dart b/mobile/lib/main.dart new file mode 100644 index 0000000..5fd2374 --- /dev/null +++ b/mobile/lib/main.dart @@ -0,0 +1,200 @@ +import 'package:firebase_core/firebase_core.dart'; +import 'package:flutter/material.dart'; +import 'firebase_options.dart'; +import 'routes.dart'; +import 'login.dart'; +import 'cart.dart'; +import 'payement_order.dart'; +import 'signup.dart'; +import 'order_history.dart'; + +void main() async { + WidgetsFlutterBinding.ensureInitialized(); + await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); + runApp(MyApp()); +} + +class MyApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Carpool App', + theme: ThemeData( + primarySwatch: Colors.blue, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: HomePage(), + routes: { + '/signup': (context) => const SignUpPage(), + '/login': (context) => const LoginPage(), + '/routes': (context) => RoutesPage(), + '/order_history': (context) => OrderHistoryPage(), + '/payment': (context) => PaymentOrderTrackingPage(), + '/cart': (context) => CartPage( + selectedRide: Ride( + name: 'Sample Ride', + startLocation: 'Sample Start', + endLocation: 'Sample End', + time: 'Sample Time', + )), + }, + ); + } +} + +class HomePage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Home'), + ), + drawer: Drawer( + child: ListView( + padding: EdgeInsets.zero, + children: <Widget>[ + const DrawerHeader( + decoration: BoxDecoration( + color: Colors.blue, + ), + child: Text( + 'Menu', + style: TextStyle( + color: Colors.white, + fontSize: 24, + ), + ), + ), + _buildDrawerItem( + icon: Icons.app_registration_rounded, + text: 'Signup', + onTap: () { + Navigator.pop(context); + Navigator.pushNamed(context, '/signup'); + }, + ), + _buildDrawerItem( + icon: Icons.login, + text: 'Login', + onTap: () { + Navigator.pop(context); + Navigator.pushNamed(context, '/login'); + }, + ), + _buildDrawerItem( + icon: Icons.map, + text: 'Routes', + onTap: () { + Navigator.pop(context); + Navigator.pushNamed(context, '/routes'); + }, + ), + _buildDrawerItem( + icon: Icons.shopping_cart, + text: 'Cart', + onTap: () { + Navigator.pop(context); + Navigator.pushNamed(context, '/cart'); + }, + ), + _buildDrawerItem( + icon: Icons.history, + text: 'Order History', + onTap: () { + Navigator.pop(context); + Navigator.pushNamed(context, '/order_history'); + }, + ), + _buildDrawerItem( + icon: Icons.payment, + text: 'Payment & Order Tracking', + onTap: () { + Navigator.pop(context); + Navigator.pushNamed(context, '/payment'); + }, + ), + ], + ), + ), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + const SizedBox(height: 20), + const Text( + 'Hello there', + style: TextStyle( + fontSize: 48, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 20), + const Text( + 'Welcome to Carpool', + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 20), + Image.asset( + 'assets/logo.png', + width: 200, + height: 200, + ), + const SizedBox(height: 40), + ElevatedButton( + onPressed: () { + Navigator.pushNamed(context, '/login'); + }, + style: ElevatedButton.styleFrom( + primary: Colors.blue, + ), + child: const Padding( + padding: EdgeInsets.symmetric(horizontal: 40, vertical: 16), + child: Text( + 'Login', + style: TextStyle( + fontSize: 18, + color: Colors.white, + ), + ), + ), + ), + const SizedBox(height: 20), + ElevatedButton( + onPressed: () { + Navigator.pushNamed(context, '/signup'); + }, + style: ElevatedButton.styleFrom( + primary: Colors.green, + ), + child: const Padding( + padding: EdgeInsets.symmetric(horizontal: 40, vertical: 16), + child: Text( + 'Signup', + style: TextStyle( + fontSize: 18, + color: Colors.white, + ), + ), + ), + ), + ], + ), + ), + ); + } + + Widget _buildDrawerItem({ + required IconData icon, + required String text, + required VoidCallback onTap, + }) { + return ListTile( + leading: Icon(icon), + title: Text(text), + onTap: onTap, + ); + } +} diff --git a/mobile/lib/order_history.dart b/mobile/lib/order_history.dart new file mode 100644 index 0000000..543a5ec --- /dev/null +++ b/mobile/lib/order_history.dart @@ -0,0 +1,181 @@ +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; + +class RideOrder { + final String orderID; + final String driverName; + final String carModel; + final Color? carColor; + final String plateNumber; + final String status; + final DateTime orderTime; + + RideOrder({ + required this.orderID, + required this.driverName, + required this.carModel, + required this.carColor, + required this.plateNumber, + required this.status, + required this.orderTime, + }); +} + +class OrderHistoryPage extends StatelessWidget { + final List<RideOrder> orders = [ + RideOrder( + orderID: '001', + driverName: 'John Doe', + carModel: 'Toyota Corolla', + carColor: Colors.black, + plateNumber: 'ABC-123', + status: 'Completed', + orderTime: DateTime.now().subtract(const Duration(days: 5)), + ), + RideOrder( + orderID: '002', + driverName: 'Alice Smith', + carModel: 'Honda Civic', + carColor: Colors.blue, + plateNumber: 'XYZ-789', + status: 'Cancelled', + orderTime: DateTime.now().subtract(const Duration(days: 2)), + ), + RideOrder( + orderID: '004', + driverName: 'Emily Johnson', + carModel: 'Chevrolet Malibu', + carColor: Colors.green, + plateNumber: 'GHI-789', + status: 'Completed', + orderTime: DateTime.now().subtract(const Duration(days: 7)), + ), + RideOrder( + orderID: '005', + driverName: 'David Wilson', + carModel: 'Tesla Model 3', + carColor: Colors.grey, + plateNumber: 'JKL-012', + status: 'Pending', + orderTime: DateTime.now().subtract(const Duration(days: 2)), + ), + RideOrder( + orderID: '006', + driverName: 'Sophia Brown', + carModel: 'BMW X5', + carColor: Colors.black, + plateNumber: 'MNO-345', + status: 'Cancelled', + orderTime: DateTime.now().subtract(const Duration(days: 4)), + ), + RideOrder( + orderID: '007', + driverName: 'James Davis', + carModel: 'Audi A4', + carColor: Colors.blueGrey, + plateNumber: 'PQR-678', + status: 'pending', + orderTime: DateTime.now().subtract(const Duration(days: 6)), + ), + RideOrder( + orderID: '008', + driverName: 'Olivia Martinez', + carModel: 'Hyundai Elantra', + carColor: Colors.orange, + plateNumber: 'STU-901', + status: 'Completed', + orderTime: DateTime.now().subtract(const Duration(days: 9)), + ), + ]; + + Color _getStatusColor(String status) { + switch (status.toLowerCase()) { + case 'completed': + return Colors.green; + case 'pending': + return Colors.orange; + case 'cancelled': + return Colors.red; + // Add more cases for other statuses + default: + return Colors.grey; + } + } + + String _formatDateTime(DateTime dateTime) { + return DateFormat('EEEE dd/MM/yyyy hh:mm a').format(dateTime); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Order History'), + ), + body: ListView.builder( + itemCount: orders.length, + itemBuilder: (BuildContext context, int index) { + final RideOrder order = orders[index]; + return Card( + elevation: 3, + margin: const EdgeInsets.symmetric(vertical: 8, horizontal: 16), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + child: ListTile( + title: Row( + children: [ + Expanded( + child: Text( + '${order.driverName} - ${order.carModel}', + style: const TextStyle( + fontWeight: FontWeight.bold, + ), + overflow: TextOverflow.ellipsis, + ), + ), + ], + ), + subtitle: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + _formatDateTime(order.orderTime), + style: const TextStyle( + fontSize: 12, + color: Colors.grey, + ), + ), + Text( + order.status, + style: TextStyle( + color: _getStatusColor(order.status), + ), + ), + ], + ), + Row( + children: [ + Icon(Icons.time_to_leave, color: order.carColor), // + const SizedBox(width: 4), + Text(order.plateNumber), + ], + ), + ], + ), + leading: const Icon(Icons + .assignment), // Use an appropriate icon for order history + onTap: () { + // Handle tapping on a specific order (if needed) + print('Selected Order ID: ${order.orderID}'); + }, + ), + ); + }, + ), + ); + } +} diff --git a/mobile/lib/payement_order.dart b/mobile/lib/payement_order.dart new file mode 100644 index 0000000..eac05ec --- /dev/null +++ b/mobile/lib/payement_order.dart @@ -0,0 +1,81 @@ +import 'package:flutter/material.dart'; +import 'credit_card_payment.dart'; + +class Order { + final String orderID; + final String rideName; + final String status; + final double amount; + + Order( + {required this.orderID, + required this.rideName, + required this.status, + required this.amount}); +} + +class PaymentOrderTrackingPage extends StatelessWidget { + final List<Order> orders = [ + Order( + orderID: '001', + rideName: 'Morning Ride - Gate 3 to Abdu-Basha', + status: 'Completed', + amount: 15.0), + Order( + orderID: '002', + rideName: 'Afternoon Ride - Abdu-Basha to Gate 3', + status: 'Pending', + amount: 12.5), + ]; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('Payment & Order Tracking'), + ), + body: ListView.builder( + itemCount: orders.length, + itemBuilder: (BuildContext context, int index) { + final Order order = orders[index]; + return GestureDetector( + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + CreditCardDetailsPage(orderID: order.orderID), + ), + ); + }, + child: Card( + elevation: 3, + margin: EdgeInsets.symmetric(vertical: 8, horizontal: 16), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + child: ListTile( + title: Text( + 'Order ID: ${order.orderID}', + style: TextStyle( + fontWeight: FontWeight.bold, + ), + ), + subtitle: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Ride: ${order.rideName}'), + Text('Status: ${order.status}'), + Text('Amount: \$${order.amount.toStringAsFixed(2)}'), + ], + ), + leading: Icon(Icons + .payment), // TODO Use an appropriate icon for payment/order tracking + ), + ), + ); + }, + ), + ); + } +} diff --git a/mobile/lib/routes.dart b/mobile/lib/routes.dart new file mode 100644 index 0000000..de5864c --- /dev/null +++ b/mobile/lib/routes.dart @@ -0,0 +1,99 @@ +import 'package:flutter/material.dart'; +import 'cart.dart'; +import 'package:intl/intl.dart'; + +class Route { + final String name; + final String startLocation; + final String endLocation; + + Route( + {required this.name, + required this.startLocation, + required this.endLocation}); +} + +class RoutesPage extends StatelessWidget { + final List<Route> dummyRoutes = [ + Route( + name: 'Morning Ride - Gate 3 to Abdu-Basha', + startLocation: 'Abassyia', + endLocation: 'Abdu-Basha Gate-3'), + Route( + name: 'Morning Ride - Abdu-Basha to 5th Settlement', + startLocation: 'Abdu-Basha', + endLocation: '5th Settlement'), + Route( + name: 'Afternoon Ride - Abdu-Basha to Gate 3', + startLocation: 'Hadayek Elkoba', + endLocation: 'Abdu-Basha Gate-6'), + ]; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Routes')), + body: ListView.builder( + itemCount: dummyRoutes.length, + itemBuilder: (BuildContext context, int index) { + final Route route = dummyRoutes[index]; + return GestureDetector( + onTap: () { + DateTime now = DateTime.now(); + String formattedDateTime = + DateFormat('EEEE dd/MM/yyyy hh:mm a').format(now); + Ride selectedRide = Ride( + name: route.name, + startLocation: route.startLocation, + endLocation: route.endLocation, + time: formattedDateTime, + ); + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => CartPage(selectedRide: selectedRide), + ), + ); + }, + child: Card( + elevation: 3, + margin: const EdgeInsets.symmetric(vertical: 8, horizontal: 16), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + child: ListTile( + title: Text( + route.name, + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + subtitle: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + const Icon(Icons.location_on, color: Colors.blue), + const SizedBox(width: 4), + Flexible(child: Text(route.startLocation)), + ], + ), + Row( + children: [ + const Icon(Icons.arrow_forward, color: Colors.blue), + const SizedBox(width: 4), + Flexible(child: Text(route.endLocation)), + ], + ), + ], + ), + leading: const Icon(Icons.directions_car), + ), + ), + ); + }, + ), + ); + } +} diff --git a/mobile/lib/signup.dart b/mobile/lib/signup.dart new file mode 100644 index 0000000..18a27ad --- /dev/null +++ b/mobile/lib/signup.dart @@ -0,0 +1,200 @@ +import 'package:flutter/material.dart'; +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:fluttertoast/fluttertoast.dart'; + +class SignUpPage extends StatefulWidget { + const SignUpPage({ + Key? key, + }) : super(key: key); + + @override + State<SignUpPage> createState() => _SignUpPageState(); +} + +class _SignUpPageState extends State<SignUpPage> { + final GlobalKey<FormState> _formKey = GlobalKey(); + + final FocusNode _focusNodePassword = FocusNode(); + final FocusNode _focusNodeConfirmPassword = FocusNode(); + final TextEditingController _controllerUsername = TextEditingController(); + final TextEditingController _controllerPassword = TextEditingController(); + final TextEditingController _corfirmPassword = TextEditingController(); + + bool _obscurePassword = true; + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.grey[300], + body: Form( + key: _formKey, + child: SingleChildScrollView( + padding: const EdgeInsets.all(30.0), + child: Column( + children: [ + const SizedBox(height: 20), + Image.asset( + "assets/logo.png", + height: 190, + ), + Text( + "Welcome ", + style: Theme.of(context).textTheme.headlineMedium, + ), + Text( + "Create your account", + style: Theme.of(context).textTheme.bodySmall, + ), + const SizedBox(height: 40), + TextFormField( + controller: _controllerUsername, + keyboardType: TextInputType.name, + decoration: InputDecoration( + labelText: "Email", + prefixIcon: const Icon(Icons.email_outlined), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(10), + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(10), + ), + ), + onEditingComplete: () => _focusNodePassword.requestFocus(), + validator: (String? value) { + if (value == null || value.isEmpty) { + return "Please enter username."; + } + + return null; + }, + ), + const SizedBox(height: 10), + TextFormField( + controller: _controllerPassword, + focusNode: _focusNodePassword, + obscureText: _obscurePassword, + keyboardType: TextInputType.visiblePassword, + decoration: InputDecoration( + labelText: "Password", + prefixIcon: const Icon(Icons.password_outlined), + suffixIcon: IconButton( + onPressed: () { + setState(() { + _obscurePassword = !_obscurePassword; + }); + }, + icon: _obscurePassword + ? const Icon(Icons.visibility_outlined) + : const Icon(Icons.visibility_off_outlined)), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(10), + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(10), + ), + ), + validator: (String? value) { + if (value == null || value.isEmpty) { + return "Please enter password."; + } + + return null; + }, |
