This is a part of form I use inside a card widget on my auth_screen.dart
file:
child: Obx(() => Form(
key: _formKey,
child: SingleChildScrollView(
child: Column(
children: <Widget>[
TextFormField(
decoration: const InputDecoration(labelText: 'E-Mail'),
keyboardType: TextInputType.emailAddress,
validator: (value) {
if (value!.isEmpty || !value.contains('@')) {
return 'Invalid email!';
}
},
onSaved: (value) {
_authData['email'] = value as String;
},
),
TextFormField(
decoration: const InputDecoration(labelText: 'Password'),
obscureText: true,
controller: _passwordController,
validator: (value) {
if (value!.isEmpty || value.length < 5) {
return 'Password is too short!';
}
},
onSaved: (value) {
_authData['password'] = value as String;
},
),
That has two TextFormField
for E-Mail an Password.
Also the related auth_controller.dart
file as following:
enum AuthMode { Signup, Login }
class AuthController extends GetxController
with GetSingleTickerProviderStateMixin {
static AuthController instance = Get.find();
Rx<dynamic>? authMode = AuthMode.Login.obs;
RxBool? isLoading = false.obs;
String? _token;
DateTime? _expiryDate;
String? _userId;
Timer? _authTimer;
final _isAuth = false.obs;
AnimationController? controller;
Animation<Offset>? slideAnimation;
Animation<double>? opacityAnimation;
late TextEditingController passwordController;
final key = GlobalKey<FormState>();
@override
void onInit() {
super.onInit();
tryAutoLogin();
controller = AnimationController(
vsync: this,
duration: const Duration(
milliseconds: 300,
),
);
slideAnimation = Tween<Offset>(
begin: const Offset(0, -1.5),
end: const Offset(0, 0),
).animate(
CurvedAnimation(
parent: controller as Animation<double>,
curve: Curves.fastOutSlowIn,
),
);
opacityAnimation = Tween(begin: 0.0, end: 1.0).animate(
CurvedAnimation(
parent: controller as Animation<double>,
curve: Curves.easeIn,
),
);
// _heightAnimation.addListener(() => setState(() {}));
passwordController = TextEditingController();
}
@override
void onClose() {
super.onClose();
passwordController.dispose();
}
bool get isAuth {
_isAuth.value = token != null;
return _isAuth.value;
}
String? get token {
if (_expiryDate != null &&
_expiryDate!.isAfter(DateTime.now()) &&
_token != null) {
return _token;
}
return null;
}
String? get userId {
return _userId;
}
Future<void> _authenticate(
String email, String password, String urlSegment) async {
// print('app is here!!!5555');
// const host = "localhost";
final host = UniversalPlatform.isAndroid ? '10.0.2.2' : '127.0.0.1';
final url = Uri.parse('http://$host:8000/api/$urlSegment');
try {
final http.Response response = await http.post(
url,
headers: {"Content-Type": "application/json"},
body: json.encode(
{
'email': email,
'password': password,
//'returnSecureToken': true,
},
),
);
// print('this is responsde ' );
// print(response);
final responseData = json.decode(response.body);
print(responseData);
if (responseData['error'] != null) {
throw HttpException(responseData['error']['message']);
} else {
_token = responseData['idToken'];
_userId = responseData['id'];
_expiryDate = DateTime.now().add(
Duration(
milliseconds: responseData['expiresIn'],
),
);
}
_autoLogout();
// update();
final prefs = await SharedPreferences.getInstance();
final userData = json.encode(
{
'token': _token,
'userId': _userId,
'expiryDate': _expiryDate!.toIso8601String(),
},
);
prefs.setString('userData', userData);
isLoading?.value = false;
// print(prefs.getString('userData'));
Get.toNamed(rootRoute);
} catch (error) {
throw error;
}
}
Future<void> signup(String email, String password) async {
return _authenticate(email, password, 'signup');
}
Future<void> login(String email, String password) async {
return _authenticate(email, password, 'sessions');
}
Future<bool> tryAutoLogin() async {
final prefs = await SharedPreferences.getInstance();
if (!prefs.containsKey('userData')) {
return false;
}
final Map<String, Object> extractedUserData = Map<String, Object>.from(
json.decode(prefs.getString('userData') as String));
final expiryDate =
DateTime.parse(extractedUserData['expiryDate'] as String);
if (expiryDate.isBefore(DateTime.now())) {
return false;
}
_token = extractedUserData['token'] as String;
_userId = extractedUserData['userId'] as String;
_expiryDate = expiryDate;
_isAuth.value = true;
_autoLogout();
return true;
}
Future<void> logout() async {
_token = null;
_userId = null;
_expiryDate = null;
if (_authTimer != null) {
_authTimer!.cancel();
_authTimer = null;
}
// update();
final prefs = await SharedPreferences.getInstance();
// prefs.remove('userData');
prefs.clear();
_isAuth.value = false;
}
void _autoLogout() {
if (_authTimer != null) {
_authTimer!.cancel();
}
final timeToExpiry = _expiryDate!.difference(DateTime.now()).inSeconds;
_authTimer = Timer(Duration(seconds: timeToExpiry), logout);
}
}
When I start the application it seems it runs with no errors but when as soon as I click on TextFormField
s to enter email or password, the virtual keyboard on the Android Emulator opens and closes immediately and doesn't let me enter anything. Also it shows the following message within the DEBUG CONSOLE:
D/InputConnectionAdaptor( 3218): The input method toggled cursor monitoring on
After So many efforts I found that instead of
StateLessWidget
Please useStatefullWidget
for the same. I hope it helps you!