Hasani
Hasani

Reputation: 3869

D/InputConnectionAdaptor( 3218): The input method toggled cursor monitoring on

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 TextFormFields 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

Upvotes: 2

Views: 11451

Answers (5)

Murali Krishna Regandla
Murali Krishna Regandla

Reputation: 1486

I use hooks_riverpod. The following code fixed the issue for me inside the build method.

final formKey = useMemoized(() => GlobalKey<FormState>());

I hope this applies if you are using flutter_hooks as well.

Upvotes: 0

arsalan qamar
arsalan qamar

Reputation: 1

I was facing the same problem. Solution is to use Stateful Widget and put the _formkey direct under the class scope and not under Widget build.

    class _SignupFormState extends State<SignupForm> {
  final _formkey = GlobalKey<FormState>();
  @override
  Widget build(BuildContext context) {
//rest of the code
}

Upvotes: 0

Altereyo
Altereyo

Reputation: 51

In my case, solution was taking GlobalKey() out of build () method

Closing keyboard:

Form(key: GlobalKey<FormState>());

Solution:

final _formKey = GlobalKey<FormState>();
Form(key: _formKey)

Upvotes: 2

Andy King
Andy King

Reputation: 1662

Setting the "key" property on the TextFormField solved this problem for me. I created the key in the initState method (although it could probably be created in other places), using the GlobalKey<FormFieldState>() constructor.

Upvotes: 0

Mustafa Lokhandwala
Mustafa Lokhandwala

Reputation: 814

After So many efforts I found that instead of StateLessWidget Please use StatefullWidget for the same. I hope it helps you!

Upvotes: 8

Related Questions