login design added
This commit is contained in:
parent
92da28e6db
commit
dbddbed8ce
BIN
assets/login/login-bg.png
Normal file
BIN
assets/login/login-bg.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.0 MiB |
BIN
assets/login/login-content.png
Normal file
BIN
assets/login/login-content.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 177 KiB |
BIN
assets/login/nhance-partner-logo.png
Normal file
BIN
assets/login/nhance-partner-logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 56 KiB |
BIN
build/flutter_assets/assets/login/login-bg.png
Normal file
BIN
build/flutter_assets/assets/login/login-bg.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.0 MiB |
BIN
build/flutter_assets/assets/login/login-content.png
Normal file
BIN
build/flutter_assets/assets/login/login-content.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 177 KiB |
BIN
build/flutter_assets/assets/login/nhance-partner-logo.png
Normal file
BIN
build/flutter_assets/assets/login/nhance-partner-logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 56 KiB |
@ -0,0 +1,35 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:nhance_app_pwa/customAppBar/toastHelper.dart';
|
||||
import 'package:nhance_app_pwa/models/environment.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'dart:convert';
|
||||
|
||||
class ApiService {
|
||||
final BuildContext context;
|
||||
|
||||
|
||||
|
||||
Future<Map<String, dynamic>> _makeGetRequest(
|
||||
Uri url, Map<String, String> headers) async {
|
||||
final response = await http.get(url, headers: headers);
|
||||
return _handleResponse(response);
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>> _makePostRequest(
|
||||
Uri url, Map<String, String> body, Map<String, String> headers) async {
|
||||
final response = await http.post(url, headers: headers, body: body);
|
||||
return _handleResponse(response);
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>> _handleResponse(http.Response response) async {
|
||||
if (response.statusCode == 200) {
|
||||
return jsonDecode(response.body);
|
||||
} else if (response.statusCode == 401) {
|
||||
await _clearLocalStorageAndRedirect();
|
||||
return {};
|
||||
} else {
|
||||
throw Exception('Failed to load data');
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,10 +1,13 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:nhance_partner/data/utils/validators.dart';
|
||||
import 'package:pinput/pinput.dart';
|
||||
import '../../../core/config/env.dart';
|
||||
import '../../../core/routing/routes.dart';
|
||||
import '../../../data/services/auth_service.dart';
|
||||
import '../../layouts/responsive_layout.dart';
|
||||
import '../../themes/indicators/text_field_theme.dart';
|
||||
|
||||
class LoginScreen extends StatefulWidget {
|
||||
@ -17,151 +20,593 @@ class LoginScreen extends StatefulWidget {
|
||||
class _LoginScreenState extends State<LoginScreen> {
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
final TextEditingController _emailController = TextEditingController();
|
||||
final TextEditingController _passwordController = TextEditingController();
|
||||
|
||||
final TextEditingController _PhoneNumberController = TextEditingController();
|
||||
final TextEditingController _otpController = TextEditingController();
|
||||
bool _isLoading = false;
|
||||
bool _obscurePassword = true;
|
||||
int stausVal = 1;
|
||||
int selectedIndex = 1;
|
||||
bool enteredEmailOrMobile = false;
|
||||
|
||||
Future<void> _handleLogin() async {
|
||||
|
||||
// Future<void> _handleLogin() async {
|
||||
// if (!_formKey.currentState!.validate()) return;
|
||||
//
|
||||
// setState(() => _isLoading = true);
|
||||
//
|
||||
// // Simulate API call
|
||||
// await Future.delayed(const Duration(seconds: 2));
|
||||
//
|
||||
// // TODO: Replace with your AuthService
|
||||
// final success =
|
||||
// _emailController.text == "test@example.com" &&
|
||||
// // _passwordController.text == "password";
|
||||
//
|
||||
// // setState(() => _isLoading = false);
|
||||
//
|
||||
// print("Succes - $success");
|
||||
// if (success) {
|
||||
// print("Ckeck 1");
|
||||
// if (mounted) {
|
||||
// print("Ckeck 2");
|
||||
// await AuthService.saveToken('1234');
|
||||
// final dynamic token = AuthService.saveToken('1234');
|
||||
// print('token - $token');
|
||||
//
|
||||
// print('AppRoutes.home');
|
||||
// context.go(AppRoutes.home);
|
||||
// print("Ckeck 3");
|
||||
// }
|
||||
// } else {
|
||||
// if (mounted) {
|
||||
// ScaffoldMessenger.of(
|
||||
// context,
|
||||
// ).showSnackBar(const SnackBar(content: Text("Invalid credentials")));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
final defaultPinTheme = PinTheme(
|
||||
width: 56,
|
||||
height: 56,
|
||||
textStyle: TextStyle(
|
||||
fontSize: 20,
|
||||
color: Color.fromRGBO(30, 60, 87, 1),
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Color.fromRGBO(234, 239, 243, 1)),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
);
|
||||
|
||||
Future<void> sendMobileOrEmailVerify() async {
|
||||
if (!_formKey.currentState!.validate()) return;
|
||||
|
||||
setState(() => _isLoading = true);
|
||||
|
||||
// Simulate API call
|
||||
await Future.delayed(const Duration(seconds: 2));
|
||||
|
||||
// TODO: Replace with your AuthService
|
||||
final success =
|
||||
_emailController.text == "test@example.com" &&
|
||||
_passwordController.text == "password";
|
||||
|
||||
setState(() => _isLoading = false);
|
||||
|
||||
print("Succes - $success");
|
||||
if (success) {
|
||||
print("Ckeck 1");
|
||||
if (mounted) {
|
||||
print("Ckeck 2");
|
||||
await AuthService.saveToken('1234');
|
||||
final dynamic token = AuthService.saveToken('1234');
|
||||
print('token - $token');
|
||||
|
||||
print('AppRoutes.home');
|
||||
context.go(AppRoutes.home);
|
||||
print("Ckeck 3");
|
||||
}
|
||||
} else {
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(
|
||||
context,
|
||||
).showSnackBar(const SnackBar(content: Text("Invalid credentials")));
|
||||
}
|
||||
}
|
||||
setState(() {
|
||||
enteredEmailOrMobile = true;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final isWeb = MediaQuery.of(context).size.width > 600;
|
||||
|
||||
return Scaffold(
|
||||
body: Center(
|
||||
child: Container(
|
||||
constraints: const BoxConstraints(maxWidth: 400),
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
decoration: isWeb
|
||||
? BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
blurRadius: 12,
|
||||
color: Colors.black.withOpacity(0.1),
|
||||
backgroundColor: Colors.white,
|
||||
body: LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
if (!ResponsiveLayout.isMobile(context)) {
|
||||
// Web layout
|
||||
return Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
color: Colors.white,
|
||||
padding: const EdgeInsets.all(40),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Image.asset(
|
||||
"assets/login/nhance-partner-logo.png",
|
||||
height: 45,
|
||||
),
|
||||
const SizedBox(height: 40),
|
||||
Expanded(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
"Welcome Back",
|
||||
style: TextStyle(
|
||||
fontSize: 50,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF425C5C),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Image.asset(
|
||||
"assets/login/login-content.png",
|
||||
height: 500,
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
const Text(
|
||||
'${'"'}Manage vsdv your policies, track quotations, and grow your business all in one place.${'"'}',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
color: Color(0xFF000000),
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
: null,
|
||||
),
|
||||
),
|
||||
// Right: Login form
|
||||
Expanded(
|
||||
child: Container(
|
||||
// padding: const EdgeInsets.all(40),
|
||||
decoration: const BoxDecoration(
|
||||
color: Colors.white,
|
||||
image: DecorationImage(
|
||||
image: AssetImage("assets/login/login-bg.png"), // <-- your image path
|
||||
fit: BoxFit.cover, // cover entire container
|
||||
),
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(40),
|
||||
bottomLeft: Radius.circular(40),
|
||||
),
|
||||
),
|
||||
child: Center( // <-- center vertically + horizontally
|
||||
child: SizedBox(
|
||||
width: 600, // keep fixed width like first design
|
||||
child: _LoginForm(context),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
} else {
|
||||
// Mobile layout
|
||||
return SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const SizedBox(height: 30),
|
||||
Image.asset(
|
||||
"assets/login/nhance-partner-logo.png",
|
||||
height: 45,
|
||||
),
|
||||
const SizedBox(height: 30),
|
||||
Text(
|
||||
"Welcome Back",
|
||||
style: TextStyle(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF425C5C),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Image.asset(
|
||||
"assets/login/login-content.png",
|
||||
height: 180 ,
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(vertical: 20,horizontal: 50 ),
|
||||
child: Text(
|
||||
'${'"'}Manage vsdv your policies, track quotations, and grow your business all in one place.${'"'}',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 11,
|
||||
color: Color(0xFF000000),
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Container(
|
||||
width: double.infinity,
|
||||
height: MediaQuery.of(context).size.height, // full screen height
|
||||
padding: const EdgeInsets.all(20),
|
||||
decoration: const BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
colors: [Color(0xFF466F6C), Color(0xFF86D5CF)],
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
),
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(40),
|
||||
topRight: Radius.circular(40),
|
||||
),
|
||||
),
|
||||
child: _LoginForm(context),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _LoginForm(BuildContext context) {
|
||||
const focusedBorderColor = Colors.white;
|
||||
const fillColor = Color.fromRGBO(243, 246, 249, 0);
|
||||
const borderColor = Color.fromRGBO(23, 171, 144, 0.4);
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
"Login to your account",
|
||||
style: TextStyle(
|
||||
fontSize: ResponsiveLayout.isMobile(context) ? 28 : 35,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
"Enter your email or mobile number to receive a one time password.",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: ResponsiveLayout.isMobile(context) ? 14 : 18,
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.w600
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.all(3),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey.shade50,
|
||||
borderRadius: BorderRadius.circular(50),
|
||||
),
|
||||
|
||||
child: Row(
|
||||
children: [
|
||||
buildTab("Mobile", 0),
|
||||
const SizedBox(width: 10),
|
||||
buildTab("Email", 1),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 30),
|
||||
Container(
|
||||
child: Form(
|
||||
key: _formKey,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
// App Logo
|
||||
Image.asset('assets/logo.png', width: 80, height: 80),
|
||||
const SizedBox(height: 20),
|
||||
|
||||
// Environment label
|
||||
Text(
|
||||
"Environment: ${Env.envName.toUpperCase()}",
|
||||
style: const TextStyle(fontSize: 14, color: Colors.grey),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
|
||||
ThemedFormField(
|
||||
hintText: 'Email',
|
||||
backgroundColor: Colors.white,
|
||||
validator: (value) => Validators.email(value, "Email"),
|
||||
// imgPath: "MiscIconAssetPath.person",
|
||||
controller: _emailController,
|
||||
// txtwidth: MediaQuery.of(context).size.width * 0.5,
|
||||
// keyboardType: TextInputType.number,
|
||||
// maxLength: 10,
|
||||
// inputFormatters: [FilteringTextInputFormatter.digitsOnly],
|
||||
// readOnly: true,
|
||||
),
|
||||
|
||||
const SizedBox(height: 16),
|
||||
ThemedFormField(
|
||||
hintText: 'Password',
|
||||
backgroundColor: Colors.white,
|
||||
validator: (value) =>
|
||||
Validators.passwordlogIn(value, "Password"),
|
||||
// imgPath: "MiscIconAssetPath.person",
|
||||
controller: _passwordController,
|
||||
isObscurable: true,
|
||||
// txtwidth: MediaQuery.of(context).size.width * 0.5,
|
||||
// keyboardType: TextInputType.number,
|
||||
// maxLength: 10,
|
||||
// inputFormatters: [FilteringTextInputFormatter.digitsOnly],
|
||||
// readOnly: true,
|
||||
),
|
||||
|
||||
// Password
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// Login Button
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
child: ElevatedButton(
|
||||
onPressed: _isLoading ? null : _handleLogin,
|
||||
child: _isLoading
|
||||
? const SizedBox(
|
||||
height: 20,
|
||||
width: 20,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2,
|
||||
valueColor: AlwaysStoppedAnimation<Color>(
|
||||
Colors.white,
|
||||
),
|
||||
),
|
||||
)
|
||||
: const Text("Login"),
|
||||
width: 400,
|
||||
height: 70,
|
||||
child: Column(
|
||||
children: [
|
||||
if (stausVal == 0)
|
||||
ThemedFormField(
|
||||
hintText: 'Email',
|
||||
backgroundColor: Colors.white,
|
||||
validator: (value) => Validators.email(value, "Email"),
|
||||
// imgPath: "MiscIconAssetPath.person",
|
||||
controller: _emailController,
|
||||
),
|
||||
if (stausVal == 1)
|
||||
ThemedFormField(
|
||||
hintText: 'Mobile Number',
|
||||
backgroundColor: Colors.white,
|
||||
validator: (value) => Validators.phone(value, "Phone"),
|
||||
// imgPath: "MiscIconAssetPath.person",
|
||||
controller: _PhoneNumberController,
|
||||
// txtwidth: MediaQuery.of(context).size.width * 0.5,
|
||||
keyboardType: TextInputType.number,
|
||||
maxLength: 10,
|
||||
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
|
||||
// readOnly: true,
|
||||
),
|
||||
// const SizedBox(height: 16),
|
||||
// ThemedFormField(
|
||||
// hintText: 'Password',
|
||||
// backgroundColor: Colors.white,
|
||||
// validator: (value) =>
|
||||
// Validators.passwordlogIn(value, "Password"),
|
||||
// // imgPath: "MiscIconAssetPath.person",
|
||||
// controller: _passwordController,
|
||||
// isObscurable: true,
|
||||
// // txtwidth: MediaQuery.of(context).size.width * 0.5,
|
||||
// // keyboardType: TextInputType.number,
|
||||
// // maxLength: 10,
|
||||
// // inputFormatters: [FilteringTextInputFormatter.digitsOnly],
|
||||
// // readOnly: true,
|
||||
// ),
|
||||
],
|
||||
)
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
if(enteredEmailOrMobile)
|
||||
Container(
|
||||
child: Text('OTP',
|
||||
style: TextStyle(
|
||||
fontSize: ResponsiveLayout.isMobile(context) ? 14 : 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Colors.white
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 12),
|
||||
|
||||
// Forgot password link
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
// TODO: Navigate to forgot password screen
|
||||
},
|
||||
child: const Text("Forgot password?"),
|
||||
if(enteredEmailOrMobile)
|
||||
Container(
|
||||
child: Pinput(
|
||||
length: 6,
|
||||
defaultPinTheme:
|
||||
defaultPinTheme,
|
||||
separatorBuilder:
|
||||
(index) =>
|
||||
const SizedBox(
|
||||
width: 8),
|
||||
showCursor: true,
|
||||
controller: _otpController,
|
||||
// validator: _validatePin,
|
||||
errorPinTheme:
|
||||
defaultPinTheme
|
||||
.copyBorderWith(
|
||||
border: Border.all(
|
||||
color: Colors
|
||||
.redAccent),
|
||||
),
|
||||
hapticFeedbackType:
|
||||
HapticFeedbackType
|
||||
.lightImpact,
|
||||
onCompleted: (pin) {
|
||||
debugPrint(
|
||||
'onCompleted: $pin');
|
||||
},
|
||||
onChanged: (value) {
|
||||
debugPrint(
|
||||
'onChanged: $value');
|
||||
},
|
||||
cursor: Column(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment
|
||||
.end,
|
||||
children: [
|
||||
Container(
|
||||
margin:
|
||||
const EdgeInsets
|
||||
.only(
|
||||
bottom: 9),
|
||||
width: 22,
|
||||
height: 1,
|
||||
color:
|
||||
focusedBorderColor,
|
||||
),
|
||||
],
|
||||
),
|
||||
focusedPinTheme:
|
||||
defaultPinTheme
|
||||
.copyWith(
|
||||
decoration:
|
||||
defaultPinTheme
|
||||
.decoration!
|
||||
.copyWith(
|
||||
borderRadius:
|
||||
BorderRadius
|
||||
.circular(8),
|
||||
border: Border.all(
|
||||
color:
|
||||
focusedBorderColor),
|
||||
),
|
||||
),
|
||||
submittedPinTheme:
|
||||
defaultPinTheme
|
||||
.copyWith(
|
||||
decoration:
|
||||
defaultPinTheme
|
||||
.decoration!
|
||||
.copyWith(
|
||||
color: fillColor,
|
||||
borderRadius:
|
||||
BorderRadius
|
||||
.circular(19),
|
||||
border: Border.all(
|
||||
color:
|
||||
focusedBorderColor),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
SizedBox(
|
||||
width: 400,
|
||||
child: SizedBox(
|
||||
width: double.infinity,
|
||||
height: 50,
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Color(0xFF436462),
|
||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
),
|
||||
onPressed: () {
|
||||
sendMobileOrEmailVerify();
|
||||
},
|
||||
child: Text(
|
||||
enteredEmailOrMobile ? 'Continue' : 'Request OTP',
|
||||
style: TextStyle(
|
||||
fontSize: ResponsiveLayout.isMobile(context) ? 18 : 20,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Colors.white
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildTab(String title, int index) {
|
||||
final isSelected = selectedIndex == index + 1;
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
selectedIndex = index + 1;
|
||||
if (selectedIndex == 2) {
|
||||
stausVal = 0;
|
||||
} else {
|
||||
stausVal = 1;
|
||||
}
|
||||
});
|
||||
},
|
||||
child: Container(
|
||||
padding:EdgeInsets.only(
|
||||
top: 6.5, bottom: 6.0, left: 40.0, right: 40.0),
|
||||
decoration: BoxDecoration(
|
||||
color: isSelected ? const Color(0xFF436462) : Colors.transparent,
|
||||
boxShadow: isSelected
|
||||
? [
|
||||
BoxShadow(
|
||||
color: isSelected
|
||||
? const Color(0xFF436462)
|
||||
: Colors.transparent, // Grey shadow
|
||||
spreadRadius: 0.2,
|
||||
blurRadius: 1,
|
||||
offset: const Offset(0, 1), // Horizontal, Vertical
|
||||
),
|
||||
]
|
||||
: [],
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
child: Text(title,
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
color: isSelected ? Colors.white : Colors.black,
|
||||
fontWeight: FontWeight.w500,
|
||||
))),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// @override
|
||||
// Widget build(BuildContext context) {
|
||||
// final isWeb = MediaQuery.of(context).size.width > 600;
|
||||
//
|
||||
// return Scaffold(
|
||||
// body: Center(
|
||||
// child: Container(
|
||||
// constraints: const BoxConstraints(maxWidth: 400),
|
||||
// padding: const EdgeInsets.all(16.0),
|
||||
// decoration: isWeb
|
||||
// ? BoxDecoration(
|
||||
// color: Colors.white,
|
||||
// borderRadius: BorderRadius.circular(8),
|
||||
// boxShadow: [
|
||||
// BoxShadow(
|
||||
// blurRadius: 12,
|
||||
// color: Colors.black.withOpacity(0.1),
|
||||
// ),
|
||||
// ],
|
||||
// )
|
||||
// : null,
|
||||
// child: Form(
|
||||
// key: _formKey,
|
||||
// child: Column(
|
||||
// mainAxisSize: MainAxisSize.min,
|
||||
// children: [
|
||||
// // App Logo
|
||||
// Image.asset('assets/logo.png', width: 80, height: 80),
|
||||
// const SizedBox(height: 20),
|
||||
//
|
||||
// // Environment label
|
||||
// Text(
|
||||
// "Environment: ${Env.envName.toUpperCase()}",
|
||||
// style: const TextStyle(fontSize: 14, color: Colors.grey),
|
||||
// ),
|
||||
// const SizedBox(height: 20),
|
||||
//
|
||||
// ThemedFormField(
|
||||
// hintText: 'Email',
|
||||
// backgroundColor: Colors.white,
|
||||
// validator: (value) => Validators.email(value, "Email"),
|
||||
// // imgPath: "MiscIconAssetPath.person",
|
||||
// controller: _emailController,
|
||||
// // txtwidth: MediaQuery.of(context).size.width * 0.5,
|
||||
// // keyboardType: TextInputType.number,
|
||||
// // maxLength: 10,
|
||||
// // inputFormatters: [FilteringTextInputFormatter.digitsOnly],
|
||||
// // readOnly: true,
|
||||
// ),
|
||||
//
|
||||
// const SizedBox(height: 16),
|
||||
// ThemedFormField(
|
||||
// hintText: 'Password',
|
||||
// backgroundColor: Colors.white,
|
||||
// validator: (value) =>
|
||||
// Validators.passwordlogIn(value, "Password"),
|
||||
// // imgPath: "MiscIconAssetPath.person",
|
||||
// controller: _passwordController,
|
||||
// isObscurable: true,
|
||||
// // txtwidth: MediaQuery.of(context).size.width * 0.5,
|
||||
// // keyboardType: TextInputType.number,
|
||||
// // maxLength: 10,
|
||||
// // inputFormatters: [FilteringTextInputFormatter.digitsOnly],
|
||||
// // readOnly: true,
|
||||
// ),
|
||||
//
|
||||
// // Password
|
||||
// const SizedBox(height: 24),
|
||||
//
|
||||
// // Login Button
|
||||
// SizedBox(
|
||||
// width: double.infinity,
|
||||
// child: ElevatedButton(
|
||||
// onPressed: _isLoading ? null : _handleLogin,
|
||||
// child: _isLoading
|
||||
// ? const SizedBox(
|
||||
// height: 20,
|
||||
// width: 20,
|
||||
// child: CircularProgressIndicator(
|
||||
// strokeWidth: 2,
|
||||
// valueColor: AlwaysStoppedAnimation<Color>(
|
||||
// Colors.white,
|
||||
// ),
|
||||
// ),
|
||||
// )
|
||||
// : const Text("Login"),
|
||||
// ),
|
||||
// ),
|
||||
//
|
||||
// const SizedBox(height: 12),
|
||||
//
|
||||
// // Forgot password link
|
||||
// TextButton(
|
||||
// onPressed: () {
|
||||
// // TODO: Navigate to forgot password screen
|
||||
// },
|
||||
// child: const Text("Forgot password?"),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
|
||||
|
||||
16
pubspec.lock
16
pubspec.lock
@ -592,6 +592,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.1.0"
|
||||
pinput:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: pinput
|
||||
sha256: "8a73be426a91fefec90a7f130763ca39772d547e92f19a827cf4aa02e323d35a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.0.1"
|
||||
platform:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -821,6 +829,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.4.0"
|
||||
universal_platform:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: universal_platform
|
||||
sha256: "64e16458a0ea9b99260ceb5467a214c1f298d647c659af1bff6d3bf82536b1ec"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
vector_math:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@ -47,6 +47,7 @@ dependencies:
|
||||
google_fonts: ^6.3.1
|
||||
intl: ^0.20.2
|
||||
flutter_hooks: ^0.21.3+1
|
||||
pinput: ^5.0.1
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
@ -66,11 +67,10 @@ dev_dependencies:
|
||||
|
||||
# The following section is specific to Flutter packages.
|
||||
flutter:
|
||||
|
||||
# The following line ensures that the Material Icons font is
|
||||
# included with your application, so that you can use the icons in
|
||||
# the material Icons class.
|
||||
generate: true
|
||||
uses-material-design: true
|
||||
assets:
|
||||
- assets/login/
|
||||
|
||||
# To add assets to your application, add an assets section, like this:
|
||||
# assets:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user