Issue
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:
Running the release build, not completely rendered:
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:myapp/helpers/FCMHelper.dart';
import 'package:myapp/helpers/SecureStorageHelper.dart';
import 'package:myapp/helpers/SharedPreferencesHelper.dart';
import 'package:myapp/models/LoginModel.dart';
import 'package:http/http.dart' as http;
import 'package:myapp/models/Token.dart';
import 'package:myapp/globals.dart' as globals;
import 'package:myapp/models/UserAndTokenModel.dart';
import 'package:myapp/pages/home_page.dart';
import 'package:myapp/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("myapp_remember_me");
setState(() {
rememberMe = rememberMe ?? false;
});
}
tryFillUserCredentials() async {
var username = await secureStorage.get("myapp_email");
var password = await secureStorage.get("myapp_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/myapp_logo.png',
height: MediaQuery.of(context).size.height * 0.20,
),
);
}
rememberMeChange(bool newValue) {
setState(() {
rememberMe = newValue;
});
}
privacyPolicyTapped() {
resetFocus();
launch("https://www.myteam.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("myapp_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("myapp_email", email);
secureStorage.set("myapp_password", password);
}
storeTokens(String loginToken, String userToken) {
secureStorage.set("myapp_login_token", loginToken);
secureStorage.set("myapp_user_token", userToken);
}
deleteUserCredentials() {
secureStorage.delete("myapp_email");
secureStorage.delete("myapp_password");
secureStorage.delete("myapp_login_token");
secureStorage.delete("myapp_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("myapp_login_token");
if (loginToken != null) autoLogin();
}
autoLogin() async {
var loginToken = await secureStorage.get("myapp_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 My App",
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: myapp
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/myapp_logo.png
- assets/myapp_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!
Solution
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.
Answered By – EggBender
Answer Checked By – Cary Denson (FlutterFixes Admin)