Solved: Why does my Flutter page sometimes not render completely in release version?

Question

Asked by EggBender on November 05, 2021 (source).

Problem

I have a Flutter app with a log in page. When I run the app in debug mode, the log in page is rendered properly when the app is opened. But when I build a apk release of the app with flutter build apk --release, install it and then open the app in the emulator, the login page is not rendered properly. See screenshots below.

Running in debug mode, properly rendered:

enter image description here

Running the release build, not completely rendered:

enter image description here

Code

Login page code:

// @dart=2.9

import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart';
// import 'package:inflecto/helpers/FCMHelper.dart';
import 'package:inflecto/helpers/SecureStorageHelper.dart';
import 'package:inflecto/helpers/SharedPreferencesHelper.dart';
import 'package:inflecto/models/LoginModel.dart';
import 'package:http/http.dart' as http;
import 'package:inflecto/models/Token.dart';
import 'package:inflecto/globals.dart' as globals;
import 'package:inflecto/models/UserAndTokenModel.dart';
import 'package:inflecto/pages/home_page.dart';
import 'package:inflecto/pages/reset_password_page.dart';
import 'package:swipedetector/swipedetector.dart';
import 'package:url_launcher/url_launcher.dart';

import '../home_page.dart';

class LoginPage extends StatefulWidget {
  @override
  _LoginPageState createState() => _LoginPageState();
}

class _LoginPageState extends State<LoginPage> {
  final _usernameController = TextEditingController();
  final _passwordController = TextEditingController();
  String loginResponse = "";
  SecureStorageHelper secureStorage;
  bool rememberMe;
  bool isFirstBuild;
  bool isKeyboardVisible = false;
  double displayWidth;
  FocusNode emailFocus;
  FocusNode passwordFocus;
  KeyboardVisibilityController keyboardVisibilityController;

  @override
  void initState() {
    init();
    delayedInit();
    super.initState();
  }

  init() {
    emailFocus = new FocusNode();
    passwordFocus = new FocusNode();
    displayWidth = 1;
    rememberMe = false;
    addKeyBoardListener();
    secureStorage = new SecureStorageHelper();
  }

  delayedInit() {
    Future.delayed(Duration.zero, () {
      getReemberMe();
      tryFillUserCredentials();
      tryAutoLogin();
    });
  }

  getReemberMe() async {
    rememberMe =
        await SharedPreferencesHelper.getBool("hjarnkraft_remember_me");
    setState(() {
      rememberMe = rememberMe ?? false;
    });
  }

  tryFillUserCredentials() async {
    var username = await secureStorage.get("hjarnkraft_email");
    var password = await secureStorage.get("hjarnkraft_password");
    setState(() {
      _usernameController.text = username;
      _passwordController.text = password;
    });
  }

  @override
  Widget build(BuildContext context) {
    hideSystemOverlay();
    setDisplayDimensions();
    return SwipeDetector(
        onSwipeDown: onSwipeDown,
        child: GestureDetector(
          onTap: onScaffoldTap,
          child: Scaffold(
            resizeToAvoidBottomInset: true,
            body: SafeArea(
              child: Stack(
                children: [
                  buildControlsLayer(),
                  buildPolicyLayer(),
                  buildVersionLayer()
                ],
              ),
            ),
          ),
        ));
  }

  buildLogo(int inFlex) {
    return Flexible(
      flex: inFlex,
      child: Image.asset(
        'assets/hjarnkraft_logo.png',
        height: MediaQuery.of(context).size.height * 0.20,
      ),
    );
  }

  rememberMeChange(bool newValue) {
    setState(() {
      rememberMe = newValue;
    });
  }

  privacyPolicyTapped() {
    resetFocus();
    launch("https://www.knowe.se/policy.html");
  }

  void resetPasswordPressed() {
    resetFocus();
    Navigator.push(
      context,
      MaterialPageRoute(builder: (context) => ResetPasswordPage()),
    );
  }

  clearUserCredentialTextfields() {
    setState(() {
      _usernameController.clear();
      _passwordController.clear();
    });
  }

  void loggaInPressed() async {
    resetFocus();
    SharedPreferencesHelper.setBool("hjarnkraft_remember_me", rememberMe);
    if (!rememberMe)
      deleteUserCredentials();
    else
      storeUserCredentials(_usernameController.text, _passwordController.text);
    var loginModel =
        new LoginModel(_usernameController.text, _passwordController.text);
    var response0 = await postLogin(loginModel);
    if (response0.statusCode == 200) {
      if (!rememberMe) clearUserCredentialTextfields();
      setState(() {
        loginResponse = "";
      });
      var loginToken = Token.fromJson(json.decode(response0.body));
      globals.loginToken = loginToken;
      var response1 = await getUserToken(loginToken.token);
      if (response1.statusCode == 200) {
        var userAndToken =
            UserAndTokenModel.fromJson(json.decode(response1.body));
        var userToken = new Token(token: userAndToken.token);
        var userModel = userAndToken.userModel;
        globals.userToken = userToken;
        globals.userModel = userModel;
        if (rememberMe) storeTokens(loginToken.token, userToken.token);
        // var fcmHelper = new FCMHelper();
        // fcmHelper.configureFCM(context);
        // fcmHelper.registerFCMToken(userModel);
        Navigator.push(
          context,
          MaterialPageRoute(builder: (context) => HomePage()),
        );
      } else
        setState(() {
          loginResponse = "Fel uppstod vid inloggning.";
        });
    } else
      setState(() {
        loginResponse = "Felaktig email eller lösenord.";
      });
  }

  storeUserCredentials(String email, String password) {
    secureStorage.set("hjarnkraft_email", email);
    secureStorage.set("hjarnkraft_password", password);
  }

  storeTokens(String loginToken, String userToken) {
    secureStorage.set("hjarnkraft_login_token", loginToken);
    secureStorage.set("hjarnkraft_user_token", userToken);
  }

  deleteUserCredentials() {
    secureStorage.delete("hjarnkraft_email");
    secureStorage.delete("hjarnkraft_password");
    secureStorage.delete("hjarnkraft_login_token");
    secureStorage.delete("hjarnkraft_user_token");
  }

  Future<http.Response> postLogin(LoginModel loginModel) {
    String data = json.encode(loginModel);
    return http.post(
        Uri.parse(globals.apiBaseUrl + "authentication/authenticate_mobile"),
        body: data,
        headers: {
          'Content-type': 'application/json',
          'Accept': 'application/json'
        });
  }

  Future<http.Response> postFCMToken(String data) {
    var userToken = globals.userToken.token;
    return http.post(Uri.parse(globals.apiBaseUrl + "/user/set_fcm_token"),
        body: data,
        headers: {
          'Content-type': 'application/json',
          'Accept': 'application/json',
          "Authorization": "Bearer $userToken"
        });
  }

  Future<http.Response> getUserToken(String loginToken) {
    return http
        .get(Uri.parse(globals.apiBaseUrl + "user/get_by_token"), headers: {
      'Content-type': 'application/json',
      'Accept': 'application/json',
      "Authorization": "Bearer $loginToken"
    });
  }

  tryAutoLogin() async {
    var loginToken = await secureStorage.get("hjarnkraft_login_token");
    if (loginToken != null) autoLogin();
  }

  autoLogin() async {
    var loginToken = await secureStorage.get("hjarnkraft_login_token");
    var response = await getUserToken(loginToken);
    if (response.statusCode == 200) {
      var userAndToken = UserAndTokenModel.fromJson(json.decode(response.body));
      var userToken = new Token(token: userAndToken.token);
      var userModel = userAndToken.userModel;
      globals.userToken = userToken;
      globals.userModel = userModel;
      // var fcmHelper = new FCMHelper();
      // fcmHelper.configureFCM(context);
      // fcmHelper.registerFCMToken(userModel);
      Navigator.push(
        context,
        MaterialPageRoute(builder: (context) => HomePage()),
      );
    } else
      showMessageDialog(
          "Inloggningssessionen utgången", "Logga in igen med dina uppgifter.");
  }

  void showMessageDialog(String title, String body) {
    try {
      showDialog(
          context: context,
          builder: (BuildContext context) {
            return AlertDialog(
              title: new Text(title),
              content: new Text(body),
            );
          });
    } catch (e) {
      print(e.toString());
    }
  }

  void usernameChange(String value) {
    print("");
  }

  void addKeyBoardListener() {
    keyboardVisibilityController = KeyboardVisibilityController();
    keyboardVisibilityController.onChange.listen(onKeyboardVisibilityChange);
  }

  Widget buildUsernameTextfieldAdaptedToKeyboard() {
    return isKeyboardVisible
        ? buildKeyBoardVisibleUsernameTextfield()
        : buildKeyBoardHiddenUsernameTextfield();
  }

  Widget buildPasswordTextfieldAdaptedToKeyboard() {
    return isKeyboardVisible
        ? buildKeyboardVisiblePasswordTextfield()
        : buildKeyboardHiddenPasswordTextfield();
  }

  Widget buildKeyBoardVisibleUsernameTextfield() {
    return Expanded(
      flex: 18,
      child: Container(
        child: Row(
          children: <Widget>[
            Spacer(
              flex: 1,
            ),
            Flexible(
              flex: 8,
              child: TextField(
                  focusNode: emailFocus,
                  controller: _usernameController,
                  autocorrect: false,
                  keyboardType: TextInputType.emailAddress,
                  maxLengthEnforcement: MaxLengthEnforcement.none,
                  onChanged: usernameChange,
                  style: TextStyle(
                      height: 1,
                      fontSize: displayWidth * globals.textFieldFontSize0),
                  decoration: InputDecoration(
                    border: OutlineInputBorder(
                        borderRadius: BorderRadius.circular(10.0)),
                    filled: true,
                    fillColor: Colors.white,
                    contentPadding: EdgeInsets.all(
                        MediaQuery.of(context).size.height * 0.02),
                    labelText: 'Epost',
                  ),
                  textCapitalization: TextCapitalization.none),
            ),
            Spacer(
              flex: 1,
            )
          ],
        ),
      ),
    );
  }

  Widget buildKeyBoardHiddenUsernameTextfield() {
    return Expanded(
      flex: 8,
      child: Container(
        child: Row(
          children: <Widget>[
            Spacer(
              flex: 1,
            ),
            Flexible(
              flex: 8,
              child: TextField(
                  focusNode: emailFocus,
                  controller: _usernameController,
                  autocorrect: false,
                  keyboardType: TextInputType.emailAddress,
                  maxLengthEnforcement: MaxLengthEnforcement.none,
                  onChanged: usernameChange,
                  style: TextStyle(
                      height: 1,
                      fontSize: displayWidth * globals.textFieldFontSize0),
                  decoration: InputDecoration(
                    border: OutlineInputBorder(
                        borderRadius: BorderRadius.circular(10.0)),
                    filled: true,
                    fillColor: Colors.white,
                    contentPadding: EdgeInsets.all(
                        MediaQuery.of(context).size.height * 0.02),
                    labelText: 'Epost',
                  ),
                  textCapitalization: TextCapitalization.none),
            ),
            Spacer(
              flex: 1,
            )
          ],
        ),
      ),
    );
  }

  Widget buildKeyboardVisiblePasswordTextfield() {
    return Flexible(
      flex: 18,
      child: Row(
        children: <Widget>[
          Spacer(
            flex: 1,
          ),
          Flexible(
            flex: 8,
            child: TextField(
                focusNode: passwordFocus,
                maxLengthEnforcement: MaxLengthEnforcement.none,
                controller: _passwordController,
                autocorrect: false,
                style: TextStyle(
                    height: 1,
                    fontSize: displayWidth * globals.textFieldFontSize0),
                decoration: InputDecoration(
                  contentPadding:
                      EdgeInsets.all(MediaQuery.of(context).size.height * 0.02),
                  border: OutlineInputBorder(
                      borderRadius: BorderRadius.circular(10.0)),
                  filled: true,
                  fillColor: Colors.white,
                  labelText: 'Lösenord',
                ),
                obscureText: true,
                textCapitalization: TextCapitalization.none),
          ),
          Spacer(
            flex: 1,
          )
        ],
      ),
    );
  }

  Widget buildKeyboardHiddenPasswordTextfield() {
    return Flexible(
      flex: 8,
      child: Row(
        children: <Widget>[
          Spacer(
            flex: 1,
          ),
          Flexible(
            flex: 8,
            child: TextField(
                focusNode: passwordFocus,
                maxLengthEnforcement: MaxLengthEnforcement.none,
                controller: _passwordController,
                autocorrect: false,
                style: TextStyle(
                    height: 1,
                    fontSize: displayWidth * globals.textFieldFontSize0),
                decoration: InputDecoration(
                  contentPadding:
                      EdgeInsets.all(MediaQuery.of(context).size.height * 0.02),
                  border: OutlineInputBorder(
                      borderRadius: BorderRadius.circular(10.0)),
                  filled: true,
                  fillColor: Colors.white,
                  labelText: 'Lösenord',
                ),
                obscureText: true,
                textCapitalization: TextCapitalization.none),
          ),
          Spacer(
            flex: 1,
          )
        ],
      ),
    );
  }

  Widget buildKeyboardAdaptedResponseForms() {
    return Expanded(
      flex: isKeyboardVisible ? 6 : 5,
      child: Row(
        mainAxisAlignment: MainAxisAlignment.start,
        crossAxisAlignment: CrossAxisAlignment.center,
        mainAxisSize: MainAxisSize.max,
        children: <Widget>[
          Spacer(
            flex: 1,
          ),
          Expanded(
            flex: 8,
            child: Container(
                child: Text("$loginResponse",
                    overflow: TextOverflow.visible,
                    style: new TextStyle(
                        fontSize: displayWidth * globals.linkFontSize0,
                        color: Colors.red),
                    textAlign: TextAlign.left)),
          ),
          Spacer(
            flex: 1,
          )
        ],
      ),
    );
  }

  Widget buildKeyboardAdaptedRememberMeForms() {
    return isKeyboardVisible
        ? Container()
        : Expanded(
            flex: 3,
            child: Row(
              mainAxisSize: MainAxisSize.max,
              mainAxisAlignment: MainAxisAlignment.start,
              crossAxisAlignment: CrossAxisAlignment.center,
              children: <Widget>[
                Spacer(
                  flex: 1,
                ),
                Expanded(
                  flex: 8,
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.start,
                    crossAxisAlignment: CrossAxisAlignment.center,
                    mainAxisSize: MainAxisSize.max,
                    children: <Widget>[
                      Container(
                        child: Text(
                          "Kom ihåg mig",
                          overflow: TextOverflow.visible,
                          style: TextStyle(
                              fontSize: displayWidth * globals.linkFontSize0),
                        ),
                      ),
                      Container(
                        child: Checkbox(
                          value: rememberMe,
                          onChanged: rememberMeChange,
                        ),
                      )
                    ],
                  ),
                ),
                Spacer(
                  flex: 1,
                )
              ],
            ),
          );
  }

  Widget buildKeyboardAdaptedIForgotPasswordLink() {
    return isKeyboardVisible
        ? Container()
        : Flexible(
            flex: 5,
            child: Row(
              mainAxisSize: MainAxisSize.max,
              crossAxisAlignment: CrossAxisAlignment.stretch,
              children: <Widget>[
                Spacer(
                  flex: 1,
                ),
                Expanded(
                  flex: 8,
                  child: Container(
                    alignment: Alignment.centerLeft,
                    child: InkWell(
                      child: Text(
                        "Jag har glömt mitt lösenord",
                        textAlign: TextAlign.left,
                        style: TextStyle(
                            decoration: TextDecoration.underline,
                            fontSize: displayWidth * 0.04),
                      ),
                      onTap: resetPasswordPressed,
                    ),
                  ),
                ),
                Spacer(
                  flex: 1,
                )
              ],
            ),
          );
  }

  buildKeyboardAdaptedButtonBar() {
    return Flexible(
        flex: isKeyboardVisible ? 14 : 6,
        child: Row(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: <Widget>[
            Spacer(
              flex: 4,
            ),
            Expanded(
                flex: 15,
                child: ElevatedButton(
                  style: ButtonStyle(
                      backgroundColor: MaterialStateColor.resolveWith(
                          (states) => Color.fromRGBO(217, 217, 217, 1))),
                  child: Text(
                    'Logga in',
                    textAlign: TextAlign.center,
                    style: new TextStyle(
                        fontSize: displayWidth * globals.buttonFontSize0,
                        color: new Color.fromRGBO(54, 104, 129, 1.0)),
                  ),
                  onPressed: loggaInPressed,
                )),
            Spacer(
              flex: 1,
            ),
            Expanded(
              flex: 15,
              child: ElevatedButton(
                style: ButtonStyle(
                    backgroundColor: MaterialStateColor.resolveWith(
                        (states) => Color.fromRGBO(217, 217, 217, 1))),
                child: Text(
                  'Avbryt',
                  style: new TextStyle(
                      fontSize: displayWidth * globals.buttonFontSize0,
                      color: new Color.fromRGBO(54, 104, 129, 1.0)),
                ),
                onPressed: () {
                  resetFocus();
                  _usernameController.clear();
                  _passwordController.clear();
                },
              ),
            ),
            Spacer(
              flex: 4,
            ),
          ],
        ));
  }

  void setDisplayDimensions() {
    if (displayWidth == 1) displayWidth = MediaQuery.of(context).size.width;
  }

  void onKeyboardVisibilityChange(bool visible) {
    setState(() {
      isKeyboardVisible = visible;
    });
  }

  hideSystemOverlay() {
    SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []);
  }

  void onScaffoldTap() {
    resetFocus();
  }

  void resetFocus() {
    try {
      if (emailFocus.hasFocus) emailFocus.unfocus();
      if (passwordFocus.hasFocus) passwordFocus.unfocus();
      if (passwordFocus.hasFocus || emailFocus.hasFocus)
        Focus.of(context).unfocus();
    } catch (e) {}
  }

  onSwipeDown() {
    resetFocus();
  }

  buildPolicyLink() {
    return InkWell(
      child: Text(
        "Sekretesspolicy",
        style: TextStyle(
            fontSize: displayWidth * globals.linkFontSize0,
            color: Colors.blue,
            decoration: TextDecoration.underline),
      ),
      onTap: privacyPolicyTapped,
    );
  }

  buildVersionNr() {
    return Text(
      "Version 1.2.9",
      style: TextStyle(
          fontSize: displayWidth * globals.linkFontSize0, color: Colors.black),
    );
  }

  buildControlsLayer() {
    return Center(
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: <Widget>[
          Spacer(flex: isKeyboardVisible ? 2 : 7),
          buildLogo(isKeyboardVisible ? 40 : 20),
          Spacer(flex: isKeyboardVisible ? 1 : 3),
          Flexible(
            flex: 10,
            child: Text(
              "Välkommen till Hjärnkraft",
              overflow: TextOverflow.visible,
              style: new TextStyle(
                  fontSize: displayWidth * globals.titleFontSIze0),
              textAlign: TextAlign.center,
            ),
          ),
          Spacer(
            flex: 7,
          ),
          buildUsernameTextfieldAdaptedToKeyboard(),
          Spacer(flex: isKeyboardVisible ? 4 : 2),
          buildPasswordTextfieldAdaptedToKeyboard(),
          isKeyboardVisible ? Spacer(flex: 2) : Container(),
          buildKeyboardAdaptedResponseForms(),
          buildKeyboardAdaptedRememberMeForms(),
          buildKeyboardAdaptedIForgotPasswordLink(),
          Spacer(flex: isKeyboardVisible ? 4 : 2),
          buildKeyboardAdaptedButtonBar(),
          Spacer(
            flex: isKeyboardVisible ? 2 : 10,
          )
        ],
      ),
    );
  }

  buildPolicyLayer() {
    return isKeyboardVisible
        ? Container()
        : Positioned(
            bottom: 10,
            left: 10,
            child: buildPolicyLink(),
          );
  }

  buildVersionLayer() {
    return isKeyboardVisible
        ? Container()
        : Positioned(bottom: 10, right: 10, child: buildVersionNr());
  }
}

pubspec.yaml:

name: inflecto
description: A new Flutter project.

version: 1.0.0+1

environment:
  sdk: ">=2.12.0 <3.0.0"

dependencies:
  http: ^0.13.4
  flutter:
    sdk: flutter
  firebase_messaging: ^11.0.0
  intl: ^0.17.0
  shared_preferences: ^2.0.8
  path_provider_platform_interface: ^2.0.1
  platform: ^3.0.2
  flutter_secure_storage: ^4.2.1
  swipedetector: ^1.2.0

  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^1.0.3
  url_launcher: ^6.0.3
  firebase_core: ^1.0.4
  flutter_keyboard_visibility: ^5.1.0

dev_dependencies:
  flutter_test:
    sdk: flutter

# For information on the generic Dart part of this file, see the
# following page: https://www.dartlang.org/tools/pub/pubspec

# The following section is specific to Flutter.
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.
  uses-material-design: true
  assets:
    - assets/hjarnkraft_logo.png
    - assets/inflecto_logo.png
    - assets/logo_small.png
    - assets/green_smiley.png
    - assets/orange_smiley.png
    - assets/red_smiley.png
    - assets/horizontal_line.png

Final thoughts and question

Why isn't the log in page rendered properly in the release build, but works in debug mode?

Thanks!

Answer

Question answered by EggBender (source).

Found Issue

I found the error now. The problem was how I used MediaQuery.of(context).size.width. I first called the setDisplayWidth() method to get the display width and then assigned the value to the dispayWidth variable. But for some reason, this didn't work in release mode. The widgets were actually rendered, however, since the setDisplayWidth() call didn't work as I intended to, all text was set to a size between 0-1 pixels, which made it look like the text/widgets weren't rendered properly. Because you can see in my code in the question how I set all text size relative to the displayWidth variable. But the displayWidth variable always had the default value 1, which made the text practically invisible.

To solve the issue described above, I removed the displayWidth variable completely and instead I fetch MediaQuery.of(context).size.width directly in the build method everytime I need the display width. See my new code below.

New Code (Solution)

import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart';
// import 'package:inflecto/helpers/FCMHelper.dart';
import 'package:inflecto/helpers/SecureStorageHelper.dart';
import 'package:inflecto/helpers/SharedPreferencesHelper.dart';
import 'package:inflecto/models/LoginModel.dart';
import 'package:http/http.dart' as http;
import 'package:inflecto/models/Token.dart';
import 'package:inflecto/globals.dart' as globals;
import 'package:inflecto/models/UserAndTokenModel.dart';
import 'package:inflecto/pages/home_page.dart';
import 'package:inflecto/pages/reset_password_page.dart';
import 'package:swipedetector/swipedetector.dart';
import 'package:url_launcher/url_launcher.dart';

import '../home_page.dart';

class LoginPage extends StatefulWidget {
  @override
  _LoginPageState createState() => _LoginPageState();
}

class _LoginPageState extends State<LoginPage> {
  final _usernameController = TextEditingController();
  final _passwordController = TextEditingController();
  String loginResponse = "";
  SecureStorageHelper secureStorage = new SecureStorageHelper();
  bool rememberMe = false;
  bool isKeyboardVisible = false;
  FocusNode emailFocus = new FocusNode();
  FocusNode passwordFocus = new FocusNode();
  KeyboardVisibilityController keyboardVisibilityController =
      new KeyboardVisibilityController();

  @override
  void initState() {
    init();
    delayedInit();
    super.initState();
  }

  init() {
    emailFocus = new FocusNode();
    passwordFocus = new FocusNode();
    rememberMe = false;
    addKeyBoardListener();
    secureStorage = new SecureStorageHelper();
  }

  delayedInit() {
    Future.delayed(Duration.zero, () async {
      await getReemberMe();
      await tryFillUserCredentials();
      await tryAutoLogin();
    });
  }

  getReemberMe() async {
    rememberMe =
        await SharedPreferencesHelper.getBool("hjarnkraft_remember_me") ??
            false;
    setState(() {
      rememberMe = rememberMe;
    });
  }

  tryFillUserCredentials() async {
    var username = await secureStorage.get("hjarnkraft_email");
    var password = await secureStorage.get("hjarnkraft_password");
    setState(() {
      _usernameController.text = username ?? "";
      _passwordController.text = password ?? "";
    });
  }

  @override
  Widget build(BuildContext context) {
    hideSystemOverlay();
    return SwipeDetector(
        onSwipeDown: onSwipeDown,
        child: GestureDetector(
          onTap: onScaffoldTap,
          child: Scaffold(
            resizeToAvoidBottomInset: true,
            body: SafeArea(
              child: Stack(
                children: [
                  buildControlsLayer(),
                  buildPolicyLayer(),
                  buildVersionLayer()
                ],
              ),
            ),
          ),
        ));
  }

  buildLogo(int inFlex) {
    return Flexible(
      flex: inFlex,
      child: Image.asset(
        'assets/hjarnkraft_logo.png',
        height: MediaQuery.of(context).size.height * 0.20,
      ),
    );
  }

  rememberMeChange(bool? newValue) {
    setState(() {
      rememberMe = newValue ?? false;
    });
  }

  privacyPolicyTapped() {
    resetFocus();
    launch("https://www.knowe.se/policy.html");
  }

  void resetPasswordPressed() {
    resetFocus();
    Navigator.push(
      context,
      MaterialPageRoute(builder: (context) => ResetPasswordPage()),
    );
  }

  clearUserCredentialTextfields() {
    setState(() {
      _usernameController.clear();
      _passwordController.clear();
    });
  }

  void loggaInPressed() async {
    resetFocus();
    SharedPreferencesHelper.setBool("hjarnkraft_remember_me", rememberMe);
    if (!rememberMe)
      deleteUserCredentials();
    else
      storeUserCredentials(_usernameController.text, _passwordController.text);
    var loginModel =
        new LoginModel(_usernameController.text, _passwordController.text);
    var response0 = await postLogin(loginModel);
    if (response0.statusCode == 200) {
      if (!rememberMe) clearUserCredentialTextfields();
      setState(() {
        loginResponse = "";
      });
      var loginToken = Token.fromJson(json.decode(response0.body));
      globals.loginToken = loginToken;
      var response1 = await getUserToken(loginToken.token);
      if (response1.statusCode == 200) {
        var userAndToken =
            UserAndTokenModel.fromJson(json.decode(response1.body));
        var userToken = new Token(token: userAndToken.token);
        var userModel = userAndToken.userModel;
        globals.userToken = userToken;
        globals.userModel = userModel;
        if (rememberMe) storeTokens(loginToken.token, userToken.token);
        // var fcmHelper = new FCMHelper();
        // fcmHelper.configureFCM(context);
        // fcmHelper.registerFCMToken(userModel);
        Navigator.push(
          context,
          MaterialPageRoute(builder: (context) => HomePage()),
        );
      } else
        setState(() {
          loginResponse = "Fel uppstod vid inloggning.";
        });
    } else
      setState(() {
        loginResponse = "Felaktig email eller lösenord.";
      });
  }

  storeUserCredentials(String email, String password) {
    secureStorage.set("hjarnkraft_email", email);
    secureStorage.set("hjarnkraft_password", password);
  }

  storeTokens(String loginToken, String userToken) {
    secureStorage.set("hjarnkraft_login_token", loginToken);
    secureStorage.set("hjarnkraft_user_token", userToken);
  }

  deleteUserCredentials() {
    secureStorage.delete("hjarnkraft_email");
    secureStorage.delete("hjarnkraft_password");
    secureStorage.delete("hjarnkraft_login_token");
    secureStorage.delete("hjarnkraft_user_token");
  }

  Future<http.Response> postLogin(LoginModel loginModel) {
    String data = json.encode(loginModel);
    return http.post(
        Uri.parse(globals.apiBaseUrl + "authentication/authenticate_mobile"),
        body: data,
        headers: {
          'Content-type': 'application/json',
          'Accept': 'application/json'
        });
  }

  Future<http.Response> postFCMToken(String data) {
    var userToken = globals.userToken.token;
    return http.post(Uri.parse(globals.apiBaseUrl + "/user/set_fcm_token"),
        body: data,
        headers: {
          'Content-type': 'application/json',
          'Accept': 'application/json',
          "Authorization": "Bearer $userToken"
        });
  }

  Future<http.Response> getUserToken(String? loginToken) {
    return http
        .get(Uri.parse(globals.apiBaseUrl + "user/get_by_token"), headers: {
      'Content-type': 'application/json',
      'Accept': 'application/json',
      "Authorization": "Bearer $loginToken"
    });
  }

  tryAutoLogin() async {
    var loginToken = await secureStorage.get("hjarnkraft_login_token");
    if (loginToken != null) autoLogin();
  }

  autoLogin() async {
    var loginToken = await secureStorage.get("hjarnkraft_login_token");
    var response = await getUserToken(loginToken);
    if (response.statusCode == 200) {
      var userAndToken = UserAndTokenModel.fromJson(json.decode(response.body));
      var userToken = new Token(token: userAndToken.token);
      var userModel = userAndToken.userModel;
      globals.userToken = userToken;
      globals.userModel = userModel;
      // var fcmHelper = new FCMHelper();
      // fcmHelper.configureFCM(context);
      // fcmHelper.registerFCMToken(userModel);
      Navigator.push(
        context,
        MaterialPageRoute(builder: (context) => HomePage()),
      );
    } else
      showMessageDialog(
          "Inloggningssessionen utgången", "Logga in igen med dina uppgifter.");
  }

  void showMessageDialog(String title, String body) {
    try {
      showDialog(
          context: context,
          builder: (BuildContext context) {
            return AlertDialog(
              title: new Text(title),
              content: new Text(body),
            );
          });
    } catch (e) {
      print(e.toString());
    }
  }

  void usernameChange(String value) {
    print("");
  }

  void addKeyBoardListener() {
    keyboardVisibilityController = KeyboardVisibilityController();
    keyboardVisibilityController.onChange.listen(onKeyboardVisibilityChange);
  }

  Widget buildUsernameTextfieldAdaptedToKeyboard() {
    return isKeyboardVisible
        ? buildKeyBoardVisibleUsernameTextfield()
        : buildKeyBoardHiddenUsernameTextfield();
  }

  Widget buildPasswordTextfieldAdaptedToKeyboard() {
    return isKeyboardVisible
        ? buildKeyboardVisiblePasswordTextfield()
        : buildKeyboardHiddenPasswordTextfield();
  }

  Widget buildKeyBoardVisibleUsernameTextfield() {
    return Expanded(
      flex: 18,
      child: Container(
        child: Row(
          children: <Widget>[
            Spacer(
              flex: 1,
            ),
            Flexible(
              flex: 8,
              child: TextField(
                  focusNode: emailFocus,
                  controller: _usernameController,
                  autocorrect: false,
                  keyboardType: TextInputType.emailAddress,
                  maxLengthEnforcement: MaxLengthEnforcement.none,
                  onChanged: usernameChange,
                  style: TextStyle(
                      height: 1,
                      fontSize: MediaQuery.of(context).size.width *
                          globals.textFieldFontSize0),
                  decoration: InputDecoration(
                    border: OutlineInputBorder(
                        borderRadius: BorderRadius.circular(10.0)),
                    filled: true,
                    fillColor: Colors.white,
                    contentPadding: EdgeInsets.all(
                        MediaQuery.of(context).size.height * 0.02),
                    labelText: 'Epost',
                  ),
                  textCapitalization: TextCapitalization.none),
            ),
            Spacer(
              flex: 1,
            )
          ],
        ),
      ),
    );
  }

  Widget buildKeyBoardHiddenUsernameTextfield() {
    return Expanded(
      flex: 8,
      child: Container(
        child: Row(
          children: <Widget>[
            Spacer(
              flex: 1,
            ),
            Flexible(
              flex: 8,
              child: TextField(
                  focusNode: emailFocus,
                  controller: _usernameController,
                  autocorrect: false,
                  keyboardType: TextInputType.emailAddress,
                  maxLengthEnforcement: MaxLengthEnforcement.none,
                  onChanged: usernameChange,
                  style: TextStyle(
                      height: 1,
                      fontSize: MediaQuery.of(context).size.width *
                          globals.textFieldFontSize0),
                  decoration: InputDecoration(
                    border: OutlineInputBorder(
                        borderRadius: BorderRadius.circular(10.0)),
                    filled: true,
                    fillColor: Colors.white,
                    contentPadding: EdgeInsets.all(
                        MediaQuery.of(context).size.height * 0.02),
                    labelText: 'Epost',
                  ),
                  textCapitalization: TextCapitalization.none),
            ),
            Spacer(
              flex: 1,
            )
          ],
        ),
      ),
    );
  }

  Widget buildKeyboardVisiblePasswordTextfield() {
    return Flexible(
      flex: 18,
      child: Row(
        children: <Widget>[
          Spacer(
            flex: 1,
          ),
          Flexible(
            flex: 8,
            child: TextField(
                focusNode: passwordFocus,
                maxLengthEnforcement: MaxLengthEnforcement.none,
                controller: _passwordController,
                autocorrect: false,
                style: TextStyle(
                    height: 1,
                    fontSize: MediaQuery.of(context).size.width *
                        globals.textFieldFontSize0),
                decoration: InputDecoration(
                  contentPadding:
                      EdgeInsets.all(MediaQuery.of(context).size.height * 0.02),
                  border: OutlineInputBorder(
                      borderRadius: BorderRadius.circular(10.0)),
                  filled: true,
                  fillColor: Colors.white,
                  labelText: 'Lösenord',
                ),
                obscureText: true,
                textCapitalization: TextCapitalization.none),
          ),
          Spacer(
            flex: 1,
          )
        ],
      ),
    );
  }

  Widget buildKeyboardHiddenPasswordTextfield() {
    return Flexible(
      flex: 8,
      child: Row(
        children: <Widget>[
          Spacer(
            flex: 1,
          ),
          Flexible(
            flex: 8,
            child: TextField(
                focusNode: passwordFocus,
                maxLengthEnforcement: MaxLengthEnforcement.none,
                controller: _passwordController,
                autocorrect: false,
                style: TextStyle(
                    height: 1,
                    fontSize: MediaQuery.of(context).size.width *
                        globals.textFieldFontSize0),
                decoration: InputDecoration(
                  contentPadding:
                      EdgeInsets.all(MediaQuery.of(context).size.height * 0.02),
                  border: OutlineInputBorder(
                      borderRadius: BorderRadius.circular(10.0)),
                  filled: true,
                  fillColor: Colors.white,
                  labelText: 'Lösenord',
                ),
                obscureText: true,
                textCapitalization: TextCapitalization.none),
          ),
          Spacer(
            flex: 1,
          )
        ],
      ),
    );
  }

  Widget buildKeyboardAdaptedResponseForms() {
    return Expanded(
      flex: isKeyboardVisible ? 6 : 5,
      child: Row(
        mainAxisAlignment: MainAxisAlignment.start,
        crossAxisAlignment: CrossAxisAlignment.center,
        mainAxisSize: MainAxisSize.max,
        children: <Widget>[
          Spacer(
            flex: 1,
          ),
          Expanded(
            flex: 8,
            child: Container(
                child: Text("$loginResponse",
                    overflow: TextOverflow.visible,
                    style: new TextStyle(
                        fontSize: MediaQuery.of(context).size.width *
                            globals.linkFontSize0,
                        color: Colors.red),
                    textAlign: TextAlign.left)),
          ),
          Spacer(
            flex: 1,
          )
        ],
      ),
    );
  }

  Widget buildKeyboardAdaptedRememberMeForms() {
    return isKeyboardVisible
        ? Container()
        : Expanded(
            flex: 3,
            child: Row(
              mainAxisSize: MainAxisSize.max,
              mainAxisAlignment: MainAxisAlignment.start,
              crossAxisAlignment: CrossAxisAlignment.center,
              children: <Widget>[
                Spacer(
                  flex: 1,
                ),
                Expanded(
                  flex: 8,
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.start,
                    crossAxisAlignment: CrossAxisAlignment.center,
                    mainAxisSize: MainAxisSize.max,
                    children: <Widget>[
                      Container(
                        child: Text(
                          "Kom ihåg mig",
                          overflow: TextOverflow.visible,
                          style: TextStyle(
                              fontSize: MediaQuery.of(context).size.width *
                                  globals.linkFontSize0),
                        ),
                      ),
                      Container(
                        child: Checkbox(
                          value: rememberMe,
                          onChanged: rememberMeChange,
                        ),
                      )
                    ],
                  ),
                ),
                Spacer(
                  flex: 1,
                )
              ],
            ),
          );
  }

  Widget buildKeyboardAdaptedIForgotPasswordLink() {
    return isKeyboardVisible
        ? Container()
        : Flexible(
            flex: 5,
            child: Row(
              mainAxisSize: MainAxisSize.max,
              crossAxisAlignment: CrossAxisAlignment.stretch,
              children: <Widget>[
                Spacer(
                  flex: 1,
                ),
                Expanded(
                  flex: 8,
                  child: Container(
                    alignment: Alignment.centerLeft,
                    child: InkWell(
                      child: Text(
                        "Jag har glömt mitt lösenord",
                        textAlign: TextAlign.left,
                        style: TextStyle(
                            decoration: TextDecoration.underline,
                            fontSize: MediaQuery.of(context).size.width * 0.04),
                      ),
                      onTap: resetPasswordPressed,
                    ),
                  ),
                ),
                Spacer(
                  flex: 1,
                )
              ],
            ),
          );
  }

  buildKeyboardAdaptedButtonBar() {
    return Flexible(
        flex: isKeyboardVisible ? 14 : 6,
        child: Row(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: <Widget>[
            Spacer(
              flex: 4,
            ),
            Expanded(
                flex: 15,
                child: ElevatedButton(
                  style: ButtonStyle(
                      backgroundColor: MaterialStateColor.resolveWith(
                          (states) => Color.fromRGBO(217, 217, 217, 1))),
                  child: Text(
                    'Logga in',
                    textAlign: TextAlign.center,
                    style: new TextStyle(
                        fontSize: MediaQuery.of(context).size.width *
                            globals.buttonFontSize0,
                        color: new Color.fromRGBO(54, 104, 129, 1.0)),
                  ),
                  onPressed: loggaInPressed,
                )),
            Spacer(
              flex: 1,
            ),
            Expanded(
              flex: 15,
              child: ElevatedButton(
                style: ButtonStyle(
                    backgroundColor: MaterialStateColor.resolveWith(
                        (states) => Color.fromRGBO(217, 217, 217, 1))),
                child: Text(
                  'Avbryt',
                  style: new TextStyle(
                      fontSize: MediaQuery.of(context).size.width *
                          globals.buttonFontSize0,
                      color: new Color.fromRGBO(54, 104, 129, 1.0)),
                ),
                onPressed: () {
                  resetFocus();
                  _usernameController.clear();
                  _passwordController.clear();
                },
              ),
            ),
            Spacer(
              flex: 4,
            ),
          ],
        ));
  }

  void onKeyboardVisibilityChange(bool visible) {
    setState(() {
      isKeyboardVisible = visible;
    });
  }

  hideSystemOverlay() {
    SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []);
  }

  void onScaffoldTap() {
    resetFocus();
  }

  void resetFocus() {
    try {
      if (emailFocus.hasFocus) emailFocus.unfocus();
      if (passwordFocus.hasFocus) passwordFocus.unfocus();
      if (passwordFocus.hasFocus || emailFocus.hasFocus)
        Focus.of(context).unfocus();
    } catch (e) {}
  }

  onSwipeDown() {
    resetFocus();
  }

  buildPolicyLink() {
    return InkWell(
      child: Text(
        "Sekretesspolicy",
        style: TextStyle(
            fontSize: MediaQuery.of(context).size.width * globals.linkFontSize0,
            color: Colors.blue,
            decoration: TextDecoration.underline),
      ),
      onTap: privacyPolicyTapped,
    );
  }

  buildVersionNr() {
    return Text(
      "Version 1.2.9",
      style: TextStyle(
          fontSize: MediaQuery.of(context).size.width * globals.linkFontSize0,
          color: Colors.black),
    );
  }

  buildControlsLayer() {
    return Center(
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: <Widget>[
          Spacer(flex: isKeyboardVisible ? 2 : 7),
          buildLogo(isKeyboardVisible ? 40 : 20),
          Spacer(flex: isKeyboardVisible ? 1 : 3),
          Flexible(
            flex: 10,
            child: Text(
              "Välkommen till Hjärnkraft",
              overflow: TextOverflow.visible,
              style: new TextStyle(
                  fontSize: MediaQuery.of(context).size.width *
                      globals.titleFontSIze0),
              textAlign: TextAlign.center,
            ),
          ),
          Spacer(
            flex: 7,
          ),
          buildUsernameTextfieldAdaptedToKeyboard(),
          Spacer(flex: isKeyboardVisible ? 4 : 2),
          buildPasswordTextfieldAdaptedToKeyboard(),
          isKeyboardVisible ? Spacer(flex: 2) : Container(),
          buildKeyboardAdaptedResponseForms(),
          buildKeyboardAdaptedRememberMeForms(),
          buildKeyboardAdaptedIForgotPasswordLink(),
          Spacer(flex: isKeyboardVisible ? 4 : 2),
          buildKeyboardAdaptedButtonBar(),
          Spacer(
            flex: isKeyboardVisible ? 2 : 10,
          )
        ],
      ),
    );
  }

  buildPolicyLayer() {
    return isKeyboardVisible
        ? Container()
        : Positioned(
            bottom: 10,
            left: 10,
            child: buildPolicyLink(),
          );
  }

  buildVersionLayer() {
    return isKeyboardVisible
        ? Container()
        : Positioned(bottom: 10, right: 10, child: buildVersionNr());
  }
}

Conclusion

Be careful with how you use MediaQuery.of(context).size.width in your apps and widgets. Always test the release version because it might behave totally differently compared to the debug version. I don't know why my first code didn't work honestly.

DART FLUTTER
SHARE: