Flutter getx ui not fully build issue on loading --release version - android

everyone, I am having an issue with the release version of the flutter app where I do get everything perfect when the apps load for the first time after installing but after exiting it and re-opening the app gives an issue with the Ui build.
This is the expected result and as I get it for the first time.
This is what I get from the second time.
Key points I noticed:
I think it has something to do with getX and get controller as I didn't get any errors before using get and recent apps I have to build using getx throwing similar errors.
When I reopen the app after some time it works then again after exiting it won't, it is a continuous process.
I am using get and separating the view, controller and bindings.
Here is my main.dart file, login_binding.dart file, login_controller.dart file and login_view.dart file respectively.
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
import 'package:sizer/sizer.dart';
import 'package:travel_mate/app/utils/my_translations.dart';
import 'package:travel_mate/app/utils/themes.dart';
import 'app/modules/Bindings/login_binding.dart';
import 'app/routes/app_pages.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await GetStorage().initStorage;
runApp(
Sizer(
builder: (BuildContext context, Orientation orientation,
DeviceType deviceType) {
var isDark = GetStorage().read('isDark');
return GetMaterialApp(
defaultTransition: Transition.cupertino,
translations: MyTranslations(),
locale: Locale('en'),
fallbackLocale: Locale('np'),
themeMode: isDark != null
? isDark
? ThemeMode.dark
: ThemeMode.light
: ThemeMode.system,
debugShowCheckedModeBanner: false,
title: "Application",
getPages: AppPages.routes,
initialRoute: GetStorage().read('token') != null
? AppPages.INITIAL
: AppPages.SECONDARY,
theme: lightTheme,
darkTheme: darkTheme,
initialBinding: LoginBinding(),
);
},
),
);
}
import 'package:get/get.dart';
import 'package:travel_mate/app/modules/Controller/auth_controller.dart';
import 'package:travel_mate/app/modules/Controller/login_controller.dart';
class LoginBinding extends Bindings {
#override
void dependencies() {
Get.put(LoginController());
Get.put(AuthController());
}
}
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
import 'package:travel_mate/app/models/user.dart';
import 'package:travel_mate/app/modules/Controller/auth_controller.dart';
import 'package:travel_mate/app/modules/views/tab/tab_view.dart';
class LoginController extends GetxController {
GlobalKey<FormState> formKey = GlobalKey();
TextEditingController emailOrUsernameController = TextEditingController();
TextEditingController passwordController = TextEditingController();
var isLoading = false.obs;
Rx<User?>? user;
#override
void dispose() {
super.dispose();
emailOrUsernameController.dispose();
passwordController.dispose();
}
final count = 0.obs;
void increment() => count.value++;
void login() async {
if (formKey.currentState!.validate()) {
isLoading.value = true;
Rx<User?> response = (await AuthController.instance
.login(emailOrUsernameController.text, passwordController.text))
.obs;
if (response.value != null) {
GetStorage().write('token', response.value!.token);
Get.offAndToNamed('/tab');
}
isLoading.value = false;
}
}
void clearFields() {
emailOrUsernameController.clear();
passwordController.clear();
}
String? validateEmailOrUsername(String? value) {
{
if (value!.isEmpty) {
return "Email or username can't be empty!";
} else if (!GetUtils.isEmail(value)) {
return "Not a valid email address!";
}
return null;
}
}
String? validatePassword(String? value) {
{
if (value!.isEmpty) {
return "Password can't be empty!";
} else if (value.length < 8) {
return "Password can't be less than 8 characters!";
}
return null;
}
}
}
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:sizer/sizer.dart';
import 'package:travel_mate/app/global_components/my_text_field.dart';
import 'package:travel_mate/app/modules/views/components/custom_button.dart';
import 'package:travel_mate/app/utils/colors.dart';
import '../Controller/login_controller.dart';
class LoginView extends GetView<LoginController> {
const LoginView({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: SingleChildScrollView(
keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,
child: Column(
children: [
Container(
margin: EdgeInsets.symmetric(horizontal: 5.w, vertical: 5.w),
//FORMS START FROM HERE
child: Form(
key: controller.formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
//Main art and logo
Center(
child: SvgPicture.asset(
'assets/images/login_art.svg',
width: 75.w,
),
),
SizedBox(
height: 1.h,
),
Center(
child: Text(
'TravelMate',
style: TextStyle(
fontFamily: 'Comic Sans Ms',
fontSize: 22.5.sp,
color: primaryColor,
),
),
),
SizedBox(
height: 2.h,
),
Text(
'login'.tr,
style: TextStyle(
fontFamily:
GoogleFonts.poppins(fontWeight: FontWeight.bold)
.fontFamily,
fontSize: 15.sp,
color: primaryColor,
),
),
SizedBox(
height: 2.h,
),
//Username Field
MyTextField(
textEditingController:
controller.emailOrUsernameController,
validator: controller.validateEmailOrUsername,
textInputAction: TextInputAction.next,
labelText: 'emailLabel'.tr,
),
SizedBox(
height: 3.h,
),
//Password Field
MyTextField(
validator: controller.validatePassword,
textEditingController: controller.passwordController,
textInputAction: TextInputAction.done,
labelText: 'passwordLabel'.tr,
isPassword: true,
),
SizedBox(
height: 3.h,
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
InkWell(
onTap: () {},
child: Text(
'forgot'.tr,
style: TextStyle(
fontFamily: GoogleFonts.poppins().fontFamily),
),
)
],
),
SizedBox(
height: 4.h,
),
//Login button
Obx(
() => CustomButton(
onTap: controller.login,
isLoading: controller.isLoading.value,
title: 'login'.tr),
),
SizedBox(
height: 4.h,
),
//Sign in with google button
SizedBox(
height: 4.h,
),
//Not registered yet button
Center(
child: Text.rich(
TextSpan(
style: TextStyle(
fontFamily: GoogleFonts.poppins().fontFamily,
fontSize: 12.sp,
// color: const Color(0xff000000),
),
children: [
TextSpan(
text: 'registerText'.tr,
),
TextSpan(
recognizer: TapGestureRecognizer()
..onTap = (() {
Get.toNamed('/sign-up');
}),
text: 'signup'.tr,
style: TextStyle(
color: const Color(0xff0189e2),
),
),
],
),
textHeightBehavior: TextHeightBehavior(
applyHeightToFirstAscent: false),
textAlign: TextAlign.center,
softWrap: false,
),
),
],
),
),
),
],
),
),
),
);
}
}

Update: after trying out some possible reasons, and delaying the call of the run app function by around 500ms I was able to resolve this issue but still not sure what is causing such an error.

Related

Error: Expected a value of type 'String', but got one of type 'Null' (in flutter)

I am trying to authenticate a user's login info in a flutter app (having a login page and signup page) using nodeJS and MongoDB, but whenever I enter a valid user and press login button, I get the following error:
Launching lib\main.dart on Chrome in debug mode...
This app is linked to the debug service: ws://127.0.0.1:50690/e09XNGpEkmc=/ws
Debug service listening on ws://127.0.0.1:50690/e09XNGpEkmc=/ws
Running with sound null safety
Connecting to VM Service at ws://127.0.0.1:50690/e09XNGpEkmc=/ws
Flutter Web Bootstrap: Auto
All validations passed
Error: Expected a value of type 'String', but got one of type 'Null'
at Object.throw_ [as throw] (http://localhost:50635/dart_sdk.js:5080:11)
at Object.castError (http://localhost:50635/dart_sdk.js:5039:15)
at Object.cast [as as] (http://localhost:50635/dart_sdk.js:5356:17)
at String.as (http://localhost:50635/dart_sdk.js:46240:19)
at authservice.AuthService.new.login (http://localhost:50635/packages/flutterform/authservice.dart.lib.js:39:67)
at login.throw (<anonymous>)
at http://localhost:50635/dart_sdk.js:40646:38
at _RootZone.runBinary (http://localhost:50635/dart_sdk.js:40515:59)
at _FutureListener.thenAwait.handleError (http://localhost:50635/dart_sdk.js:35449:33)
at handleError (http://localhost:50635/dart_sdk.js:36015:51)
at _Future._propagateToListeners (http://localhost:50635/dart_sdk.js:36041:17)
at [_completeError] (http://localhost:50635/dart_sdk.js:35878:23)
at [_completeError] (http://localhost:50635/dart_sdk.js:35358:36)
at _SyncCompleter.new.completeError (http://localhost:50635/dart_sdk.js:35282:29)
at onError (http://localhost:50635/dart_sdk.js:35122:49)
at _RootZone.runBinary (http://localhost:50635/dart_sdk.js:40515:59)
at _FutureListener.then.handleError (http://localhost:50635/dart_sdk.js:35449:33)
at handleError (http://localhost:50635/dart_sdk.js:36015:51)
at _Future._propagateToListeners (http://localhost:50635/dart_sdk.js:36041:17)
at [_completeError] (http://localhost:50635/dart_sdk.js:35878:23)
at async._AsyncCallbackEntry.new.callback (http://localhost:50635/dart_sdk.js:35927:31)
at Object._microtaskLoop (http://localhost:50635/dart_sdk.js:40778:13)
at _startMicrotaskLoop (http://localhost:50635/dart_sdk.js:40784:13)
at http://localhost:50635/dart_sdk.js:36261:9
Application finished.
Exited (sigterm)
I am running the code in VSCode editor and my server is running in Heroku.
Here are my codes:
From main.dart:
import 'package:flutter/material.dart';
import '../../signup.dart';
import '../../login.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of our application.
#override
Widget build(BuildContext context) {
return MaterialApp(
// Application name
title: 'Registration Form',
// Application theme data, we can set the colors for the application as
// you want
theme: ThemeData(
primarySwatch: Colors.orange,
),
home: MySignUpPage(),
routes: {
'register': (context) => MySignUpPage(),
'login': (context) => MyLoginPage(),
},
);
}
}
From login.dart:
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import '../../authservice.dart';
class MyLoginPage extends StatefulWidget {
#override
LoginForm createState() {
return LoginForm();
}
}
class LoginForm extends State<MyLoginPage> {
final formKey = GlobalKey<FormState>();
final passwordController = TextEditingController();
final confirmpasswordController = TextEditingController();
var name, password, token;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
// The title text which will be shown on the action bar
title: Text('Registration'),
),
body: Container(
padding: EdgeInsets.symmetric(
vertical: 50.0,
horizontal: 10.0,
),
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("images/signupimg.jpg"),
fit: BoxFit.cover,
),
),
child: Form(
key: formKey,
child: Column(
children: <Widget>[
Container(
margin: EdgeInsets.all(2),
padding: const EdgeInsets.all(8.0),
child: const Align(
alignment: Alignment.topLeft,
child: Text(
'Login',
style: TextStyle(
fontSize: 40,
fontWeight: FontWeight.bold,
),
textAlign: TextAlign.left,
))),
Container(
margin: EdgeInsets.all(2),
padding: const EdgeInsets.all(8.0),
child: TextFormField(
autovalidateMode: AutovalidateMode.onUserInteraction,
validator: (String? val) {
if (val == null || val.isEmpty) {
return 'Username cannot be empty';
} else {
name = val;
}
return null;
},
decoration: InputDecoration(
filled: true, //<-- SEE HERE
fillColor: Colors.white,
labelText: 'Username',
hintText: 'Your Username',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(20.0),
)),
),
),
Container(
margin: EdgeInsets.all(2),
padding: const EdgeInsets.all(8.0),
child: TextFormField(
obscureText: true,
controller: passwordController,
autovalidateMode: AutovalidateMode.onUserInteraction,
validator: (String? val) {
if (val == null || val.isEmpty) {
return 'Password cannot be empty';
} else if (val.length < 6) {
return 'Password must be at least 6 characters long.';
} else {
password = val;
}
return null;
},
decoration: InputDecoration(
filled: true, //<-- SEE HERE
fillColor: Colors.white,
labelText: 'Password',
hintText: 'Your password',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(20.0),
)),
),
),
Container(
margin: EdgeInsets.all(10),
padding: EdgeInsets.all(10),
child: ElevatedButton(
child: Text(
"Login",
style: TextStyle(fontSize: 20),
),
onPressed: () {
AuthService().login(name, password).then((val) {
if (val.data['success'] != null) {
token = val.data!['token'];
Fluttertoast.showToast(
msg: 'Authenticated',
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.BOTTOM,
backgroundColor: Colors.white,
textColor: Colors.white,
fontSize: 16.0,
);
}
});
if (formKey.currentState!.validate()) {
debugPrint('All validations passed');
}
style:
ElevatedButton.styleFrom(
primary: Colors.orange, // Background color
onPrimary: Colors.black, //Text Color (Foreground color)
elevation: 3, //elevation of button
shape: RoundedRectangleBorder(
//to set border radius to button
borderRadius: BorderRadius.circular(35)),
);
},
),
),
Container(
margin: EdgeInsets.all(10),
child: Text(
"Don't have an account?",
style: TextStyle(fontSize: 16),
),
),
Container(
child: TextButton(
onPressed: () {
Navigator.pushNamed(context, 'register');
},
child: Text("Sign up",
style: TextStyle(
decoration: TextDecoration.underline,
fontSize: 18,
color: Colors.orange,
))))
],
),
),
),
);
}
}
From authservice.dart (which holds the login function and connection details to my server):
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:fluttertoast/fluttertoast.dart';
class AuthService {
Dio dio = new Dio();
login(String name, String password) async {
try {
return await dio.post(
'https://flutter-collegeapp.herokuapp.com/authenticate',
data: {"name": name, "password": password},
options: Options(contentType: Headers.formUrlEncodedContentType));
} on DioError catch (e) {
Fluttertoast.showToast(
msg: (e.response?.data['msg']),
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.BOTTOM,
backgroundColor: Colors.white,
textColor: Colors.orange[900],
fontSize: 16.0,
);
}
}
}
I have followed this youtube tutorial to write this code (have made some changes due to new updates in flutter)
https://www.youtube.com/watch?v=2D_76lkyF1c&t=4903s
Can someone please tell me what is wrong and why this error is occuring?

flutter error type 'Null' is not a subtype of type 'String'

so i want to print user name and user username in the profile page and in the end it shows it but for a few seconds there is a red screen that says The following _TypeError was thrown building Profile_page(dirty, state: _Profile_pageState#68414):
type 'Null' is not a subtype of type 'String'
this is the code of main.dart
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:gp1_7_2022/screen/auth/signup/userInfo/name.dart';
import 'package:gp1_7_2022/screen/auth/signup/Questions/question1.dart';
import 'package:gp1_7_2022/screen/auth/signup/Questions/question2.dart';
import 'package:gp1_7_2022/screen/auth/signup/Questions/question3.dart';
import 'package:gp1_7_2022/screen/auth/signup/Questions/question4.dart';
import 'package:gp1_7_2022/screen/auth/signup/Questions/question5.dart';
import 'package:gp1_7_2022/screen/auth/signup/userInfo/photo.dart';
import 'package:gp1_7_2022/screen/home/Profile_Page.dart';
import 'package:firebase_core/firebase_core.dart';
/*pages */
import 'package:gp1_7_2022/screen/auth/signup_login.dart';
import 'package:gp1_7_2022/screen/auth/signup/userAuth/signup.dart';
import 'package:gp1_7_2022/screen/auth/Login/login.dart';
import 'package:gp1_7_2022/screen/auth/signup/userAuth/signupConfirmationCode.dart';
import 'package:gp1_7_2022/screen/auth/signup/userAuth/signupPassword.dart';
import 'package:gp1_7_2022/screen/auth/signup/userInfo/signupBirthday.dart';
import 'package:gp1_7_2022/screen/auth/signup/userInfo/signupUsername.dart';
import 'package:gp1_7_2022/screen/auth/Login/forget_password.dart';
import 'package:gp1_7_2022/screen/settings.dart';
void main() async{
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(
MaterialApp(
initialRoute: "/",
routes: {
"/": (context) => MainPage(),
"/signup": (context)=> Signup(),
'/login':(context)=>Login(),
'/Profile_Page':(context) => Profile_page(uid: FirebaseAuth.instance.currentUser!.uid),
// '/confirmationCode':(context) => ConfirmationCode(),
// '/signupPassword':(context) => signupPassword(),
'/signupBirthday':(context) => SignupBirthday(),
'/signupUsername':(context) => SignupUsername(),
'/forget_password':(context) => forget_password(),
'/name':(context) => name(),
'/question1':(context) => question1(),
'/question2':(context) => question2(),
'/question3':(context) => question3(),
'/question4':(context) => question4(),
'/question5':(context) => question5(),
'/photo':(context) => Photo(),
'/settings':(context) => settings(),
}
)
);
}
class MainPage extends StatelessWidget {
const MainPage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot){
if(snapshot.connectionState==ConnectionState.waiting){
return const Center(child: CircularProgressIndicator());
}else if(snapshot.hasError){
return const Center(child: Text("Something went wrong!"));
}else if(snapshot.hasData){
if(FirebaseAuth.instance.currentUser!.emailVerified && FirebaseAuth.instance.currentUser!.uid != null ){
String uid = FirebaseAuth.instance.currentUser!.uid;
return Profile_page(uid: uid );
}else{
String? x = FirebaseAuth.instance.currentUser!.email;
String y= x??" ";
return ConfirmationCode(email: y);
}
} else{
return const Signup_Login();
}
},
),
);
}
}
this is the code of profile_page.dart
// import 'dart:html';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:focused_menu/focused_menu.dart';
import 'package:focused_menu/modals.dart';
/*pages */
/*colors */
import 'package:gp1_7_2022/config/palette.dart';
import 'package:gp1_7_2022/Widgets/follow_button.dart';
import 'package:rflutter_alert/rflutter_alert.dart';
import 'package:gp1_7_2022/screen/settings.dart';
class Profile_page extends StatefulWidget {
final uid;
const Profile_page({Key? key, required this.uid}) : super(key: key);
#override
State<Profile_page> createState() => _Profile_pageState();
}
class _Profile_pageState extends State<Profile_page> {
var padding= 0.8;
var userData = {};
#override
void initState() {
super.initState();
getData();
}
/* get data method */
getData() async {
try {
if (widget.uid != null) {
var userSnap = await FirebaseFirestore.instance.collection('users').doc(
widget.uid).get();
userData = userSnap.data()!;
setState(() {
});
}
}
catch(e){
Alert(
context: context,
title: "Something went wrong!",
desc: e.toString(),
).show();
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Palette.backgroundColor,
appBar: AppBar(
//appBar style
elevation: 0,
backgroundColor: Palette.backgroundColor,
automaticallyImplyLeading: false,//no arrow
//username
title: Padding(
padding: EdgeInsets.fromLTRB(5, 0, 0, 0),
child: Text(
userData['username'],
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: 24,
),
),
),
//setting icon
actions:[
FocusedMenuHolder(
//
menuWidth: MediaQuery.of(context).size.width * 0.4,
menuOffset: 0,
menuItemExtent: 49,
//list
menuItems: [
FocusedMenuItem(
title: const Text("Log out"),
trailingIcon: const Icon(Icons.logout),
onPressed: (){
/*go to sign up page*/
Navigator.pushNamed(context, '/');
return FirebaseAuth.instance.signOut();
}
),
FocusedMenuItem(
title: const Text("Settings"),
trailingIcon: const Icon(Icons.settings),
onPressed: (){
Navigator.of(context).popAndPushNamed('/settings');
},
),
],
openWithTap: true,
onPressed: (){},
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24),
child: Image.asset(
"assets/menu-icon.png",
height: 25,
width: 25,
),
),
),
],
),
body: ListView(
children: [
Container(
margin: const EdgeInsets.all(16),
child: Column(
children: [
Row(
children: [
//user photo
const Padding(
padding: EdgeInsets.fromLTRB(0, 0, 40, 0),
child: CircleAvatar(
backgroundColor: Colors.white ,
child: Icon(
Icons.account_circle_sharp,
color: Colors.grey,
size: 90,
),
),
),
//end user photo
Expanded(
flex: 7,
child: Column(
children: [
SizedBox(height:40,),
//post, followers and following
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
buildStatColumn(20, "posts"),
buildStatColumn(150, "Followers"),
buildStatColumn(10, "Following"),
],
),
//end post, followers and following
],
),
),
],
),
//username
Container(
alignment: Alignment.centerLeft,
padding: EdgeInsets.fromLTRB(10, 40, 0, 0),
child: Text(
userData['name'],
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
),
//end of username
//bio
Container(
alignment: Alignment.centerLeft,
padding: const EdgeInsets.fromLTRB(10, 1, 0, 0),
child: const Text(
'bio',
style: TextStyle(
fontSize: 16,
),
),
),
//end of bio
//edit profile button
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
// mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
FollowButton(
text: 'Edit profile',
backgroundColor: Palette.backgroundColor,
borderColor: Palette.grey,
textColor: Colors.black,
function: () {},
)
],
),
//end of button
],
),
),
],
),
);
}
}
// function to show following/followers/# of posts
Column buildStatColumn(int num, String label) {
return Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
num.toString(),
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
Container(
margin: const EdgeInsets.only(top: 4),
child: Text(
label,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w400,
color: Colors.grey,
),
),
),
],
);
}
enter image description here
Show some other widgets until data is not fully loaded.
class _Profile_pageState extends State<Profile_page> {
...
bool _isloaded = false; // Add this boolean
In getData function
getData() async {
try {
...
setState(() {
_isloaded = true; // when data is loaded update state
});
}
...
In build, return widget according to data(user)
#override
Widget build(BuildContext context) {
return _isloaded == false ?
Center(
child: CircularProgressIndicator(), // Show indicator
)
: Scaffold(
backgroundColor: Palette.backgroundColor,
...
); //Scaffold
You're assuring flutter that the data isn't null which will result in a momentary error. You can try either setting a load bool that sets to true when the data arrives or using the ?? operator. e.g userData['name'] ?? "loading" which will print loading incase the userData['name'] is null

Firebase Auth - Doesnt login issue

Basically my app has a AuthWrapper where it either goes loginPage or homePage.
class Wrapper extends ConsumerWidget {
#override
Widget build(BuildContext context, ScopedReader watch) {
final res = watch(authControllerProvider);
if (res != null) {
return HomePage();
} else {
return LoginPage();
}
}
}
On App start, it logins fine if logged in or goes loginpage if not, but for example:
if not logged in, goes login page, and if user goes register screen and registers it doesnt login, basically after pushing to pages, the AuthWrapper doesnt work, is there a way to resolve this.
registerpage.dart
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:hubx/screens/HomePage/homepage.dart';
import 'package:hubx/screens/authentication/loginPage.dart';
import 'package:hubx/services/auth.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:hubx/shared/theme/theme_colors.dart';
import 'package:hubx/shared/widgets/loading_widget.dart';
import 'package:hubx/shared/widgets/theme_widgets.dart';
import 'package:hubx/shared/validator.dart';
import 'package:theme_provider/theme_provider.dart';
class RegisterPage extends ConsumerWidget {
#override
Widget build(BuildContext context, ScopedReader watch) {
final GlobalKey<FormState> _registerFormKey = GlobalKey<FormState>();
final TextEditingController _displayNameController =
TextEditingController();
final TextEditingController _emailController = TextEditingController();
final TextEditingController _passwordController = TextEditingController();
final FocusNode _displayNameFocusNode = FocusNode();
final FocusNode _emailFocusNode = FocusNode();
final FocusNode _passwordFocusNode = FocusNode();
return GestureDetector(
onTap: () {
_displayNameFocusNode.unfocus();
_emailFocusNode.unfocus();
_passwordFocusNode.unfocus();
},
child: Scaffold(
appBar: SAppBar(context, 'Register'),
body: SafeArea(
child: Scrollbar(
child: Center(
child: SingleChildScrollView(
padding: EdgeInsets.all(16),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Card(
color:
(ThemeProvider.controllerOf(context).currentThemeId ==
'dark')
? MyThemesColor.darkBG
: MyThemesColor.lightBG,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(16))),
child: Form(
key: _registerFormKey,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Column(
children: [
TextFormField(
controller: _displayNameController,
focusNode: _displayNameFocusNode,
keyboardType: TextInputType.text,
textInputAction: TextInputAction.next,
autovalidateMode:
AutovalidateMode.onUserInteraction,
validator: (value) =>
Validator.validateField(
value: value!,
fieldName: 'Display Name'),
decoration: InputDecoration(
labelText: 'Display Name',
prefixIcon: Icon(
Icons.format_color_text_outlined)),
),
SizedBox(height: 8),
TextFormField(
controller: _emailController,
focusNode: _emailFocusNode,
keyboardType: TextInputType.emailAddress,
textInputAction: TextInputAction.next,
autovalidateMode:
AutovalidateMode.onUserInteraction,
validator: (value) =>
Validator.validateEmail(email: value!),
decoration: InputDecoration(
labelText: 'Email',
prefixIcon: Icon(Icons.email_outlined)),
),
SizedBox(height: 8),
TextFormField(
controller: _passwordController,
focusNode: _passwordFocusNode,
keyboardType: TextInputType.text,
textInputAction: TextInputAction.go,
autovalidateMode:
AutovalidateMode.onUserInteraction,
validator: (value) =>
Validator.validatePassword(
password: value!,
),
obscureText: true,
decoration: InputDecoration(
labelText: 'Password',
prefixIcon: Icon(Icons.password_outlined),
),
),
SizedBox(height: 32),
],
),
Consumer(
builder: (context, ref, child) {
final authService = ref(authServiceProvider);
if (!authService.isLoading) {
return Container(
width: double.maxFinite,
child: ElevatedButton.icon(
onPressed: () async {
_displayNameFocusNode.unfocus();
_emailFocusNode.unfocus();
_passwordFocusNode.unfocus();
if (_registerFormKey.currentState!
.validate()) {
final authService = context
.read(authServiceProvider);
await authService
.registerWithEmailAndPassword(
_emailController.text,
_passwordController.text,
_displayNameController.text,
'',
)
.then((value) {
if (value != 'Success') {
Fluttertoast.showToast(
msg: value,
);
}
});
}
},
icon: FaIcon(FontAwesomeIcons.userEdit),
label: Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
'REGISTER',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
letterSpacing: 2,
),
),
),
),
);
} else {
return LoadingWidget(
loadingSize: 30,
loadingColor: MyThemesColor.theme,
title: '',
);
}
},
),
],
),
),
),
),
SizedBox(height: 16.0),
Consumer(
builder: (context, ref, child) {
final authService = ref(authServiceProvider);
if (!authService.isLoading) {
return InkWell(
onTap: () {
Navigator.of(context)
.pushReplacement(MaterialPageRoute(
builder: (context) => LoginPage(),
));
},
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
'Already have an account? ',
style: TextStyle(letterSpacing: 0.5),
),
Text(
'Login',
style: TextStyle(
letterSpacing: 0.5,
color: MyThemesColor.theme,
fontWeight: FontWeight.w500,
),
),
],
),
);
}
return SizedBox.shrink();
},
),
],
),
),
),
),
),
),
);
}
}
authControllerProvider:
import 'dart:async';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:hubx/repositories/auth_repository.dart';
final authControllerProvider = StateNotifierProvider<AuthController, User?>(
(ref) => AuthController(ref.read)..appStarted(),
);
class AuthController extends StateNotifier<User?> {
final Reader _read;
StreamSubscription<User?>? _authStateChangesSubscription;
AuthController(this._read) : super(null) {
_authStateChangesSubscription?.cancel();
_authStateChangesSubscription = _read(authRepositoryProvider)
.authStateChanges
.listen((user) => state = user);
}
#override
void dispose() {
_authStateChangesSubscription?.cancel();
super.dispose();
}
void appStarted() async {
final user = _read(authRepositoryProvider).getCurrentUser();
if (user != null) {
Fluttertoast.showToast(msg: '######### SIGNED IN');
print('######### SIGNED IN');
} else {
Fluttertoast.showToast(msg: '######### NOT SIGNED IN');
print('######### NOT SIGNED IN');
}
}
void signOut() async {
await _read(authRepositoryProvider).signOut();
}
}
You should navigate to the wrapper after registration. And then the provider will take care of where to navigate to based on authentication state.
final authService = context.read(authServiceProvider);
var value = await authService.registerWithEmailAndPassword(
_emailController.text,
_passwordController.text,
_displayNameController.text,
);
if (value != 'Success') {
Fluttertoast.showToast(
msg: value,
);
Navigator.of(context).push(MaterialPageRoute(builder: (context) => Wrapper(),));
}

update the state of the button by getting a boolean value from firebase realtime database in Flutter

I am trying to control my switch by getting value from firebase realtime database. Its listening to the boolean value whenever it is changed but i dont understand how to use that value to toggle the button when the value in realtime database changed. This is basically an app in which you can control the switch via app and app via hardware with realtime database firebase as a bridge between them.
Here is my main.dart file:
import 'package:firebaseiot/screens/iotscreen.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
routes: <String, WidgetBuilder>{
'iotscreen/': (BuildContext context) => IotScreen()
},
title: "Firebase IOT",
debugShowCheckedModeBanner: false,
theme:
ThemeData(
brightness: Brightness.dark,
backgroundColor: Colors.black
),
themeMode: ThemeMode.system,
home: IotScreen(),
);
}
}
And here is my iotscreen.dart file:
import 'dart:async';
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class IotScreen extends StatefulWidget {
#override
_IotScreenState createState() => _IotScreenState();
}
class _IotScreenState extends State<IotScreen> {
#override
final DatabaseReference = FirebaseDatabase.instance.reference();
bool state = false;
bool newValue;
onUpdate() {
setState(() {
state = !state;
});
}
void getStatus() async {
String newValue = (await DatabaseReference.child("LightState/switch").once()).value;
print(newValue);
print(state);
setState(() {
if (newValue == 'TRUE' || newValue == 'true') {
state = true;
} else if(newValue == 'FALSE' || newValue == 'false') {
state = false;
}
});
}
Widget build(BuildContext context) {
SystemChrome.setPreferredOrientations(
[DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]);
return Scaffold(
body: StreamBuilder(
//stream: DatabaseReference.child("LightState").onValue,
builder: (context, snapshot) {
if (snapshot.hasData &&
!snapshot.hasError &&
snapshot.data.snapshot.value != null) {
return Column(
children: [
Padding(
padding: EdgeInsets.all(20),
child: SafeArea(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Icon(
Icons.clear_all,
color: Colors.black,
),
Text(
"MY ROOM",
style: TextStyle(
fontSize: 20, fontWeight: FontWeight.bold),
),
Icon(Icons.settings)
],
),
),
),
SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Column(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
"Temperature",
style: TextStyle(
fontSize: 20, fontWeight: FontWeight.bold),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
"30", // test data
style: TextStyle(
fontSize: 20, fontWeight: FontWeight.bold),
),
),
],
),
],
),
SizedBox(height: 20),
Column(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
"Humidity",
style: TextStyle(
fontSize: 20, fontWeight: FontWeight.bold),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
"80", // test data
style: TextStyle(
fontSize: 20, fontWeight: FontWeight.bold),
),
),
],
),
SizedBox(height: 80),
FloatingActionButton.extended(
onPressed: () async {
onUpdate();
onWrite();
await getStatus();
print(state);
},
label: state ? Text("ON") : Text("OFF"),
elevation: 20,
backgroundColor: state ? Colors.yellow : Colors.white,
icon: state
? Icon(Icons.visibility)
: Icon(Icons.visibility_off),
)
],
);
} else
return Container();
},
stream: DatabaseReference.child("LightState").onValue),
);
}
Future<void> onWrite() async {
DatabaseReference.child("LightState").set({"switch": !state});
}
}
And here is my .json file:
{
"LightState" : {
"switch" : true
}
}
Please help me in using the value listened to toggle the button when the value in the realtime database changed from 'false' to 'true'. I use this flutter library 'firebase_database: ^7.1.1' (https://pub.dev/packages/firebase_database)

FLUTTER - Can someone help me get this post button to execute?

I hope you all are doing well today. I have another flutter issue that I have been stuck on for the past few days now. I'm attempting to upload this data to my firestore instance, but my post button never seems to be triggering. I have attempted to print a statement from the method that it evokes, but I can't seem to get that to work either. I'm attempting to create a social media app, and any and all help would be appreciated.
My main goal is to get the post button to execute in upload.dart.
I have also included home.dart since the two classes are connected in terms of performance.
upload.dart
import 'dart:io';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:fluttermedia/models/user.dart';
import 'package:fluttermedia/pages/home.dart';
import 'package:fluttermedia/widgets/progress.dart';
import 'package:image_picker/image_picker.dart';
import 'package:path_provider/path_provider.dart';
import 'package:image/image.dart' as Im;
import 'package:uuid/uuid.dart';
class Upload extends StatefulWidget {
final User currentUser;
Upload({this.currentUser});
#override
_UploadState createState() => _UploadState();
}
class _UploadState extends State<Upload> {
TextEditingController locationController = TextEditingController();
TextEditingController captionController = TextEditingController();
File file;
bool isUploading = false;
String postId = Uuid().v4();
handleChooseFromGallery() async{
Navigator.pop(context);
File file = await ImagePicker.pickImage(source: ImageSource.gallery);
setState(() {
this.file = file;
});
}
handleTakePhoto() async {
Navigator.pop(context);
File file = await ImagePicker.pickImage(source: ImageSource.camera,maxHeight: 675,maxWidth: 960);
setState(() {
this.file = file;
});
}
selectImage(parentContext){
return showDialog(
context: parentContext,
builder: (context) {
return SimpleDialog(
title: Text("Create Post"),
children: <Widget>[
SimpleDialogOption(
child: Text("Photo With Camera"),
onPressed: handleTakePhoto,
),
SimpleDialogOption(
child: Text("Image from Gallery"),
onPressed: handleChooseFromGallery,
),
SimpleDialogOption(
child: Text("Cancel"),
onPressed: () => Navigator.pop(context),
),
],
);
}
);
}
Container buildSplashScreen(){
return Container(
color: Theme.of(context).accentColor.withOpacity(0.6),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
SvgPicture.asset('assets/images/upload.svg',height: 260.0,),
Padding(
padding: EdgeInsets.only(top:20.0),
child: RaisedButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0),
),
child: Text(
"Upload Image",
style: TextStyle(
color: Colors.white,
fontSize: 22.0,
),
),
color: Colors.deepOrange,
onPressed: () => selectImage(context),
),
)
],
),
);
}
clearImage(){
setState(() {
file = null;
});
}
//This compresses images for firebase
compressImage() async{
final tempDir = await getTemporaryDirectory();
final path = tempDir.path;
Im.Image imageFile = Im.decodeImage(file.readAsBytesSync());
final compressedImageFile = File('$path/img_$postId.jpg')..writeAsBytesSync(Im.encodeJpg(imageFile,quality: 85));
setState(() {
file = compressedImageFile;
});
}
Future<String> uploadImage(imageFile) async{
StorageUploadTask uploadTask = storageRef.child("post_$postId.jpg").putFile(imageFile);
StorageTaskSnapshot storageSnap = await uploadTask.onComplete;
String downloadUrl = await storageSnap.ref.getDownloadURL();
return downloadUrl;
}
//upload new info to firestore that creates a new collection
createPostInFirestore({String mediaUrl, String location, String description}){
postsRef.document(widget.currentUser.id)
.collection("userPosts")
.document(postId)
.setData({
"postId": postId,
"ownerId": widget.currentUser.id,
"username": widget.currentUser.username,
"mediaUrl": mediaUrl,
"description": description,
"location": location,
"timestamp": timeStamp,
"likes":{}
});
}
//Getting the info from the caption, location and pic
handleSubmit() async{
setState(() {
isUploading = true;
});
await compressImage();
String mediaUrl = await uploadImage(file);
createPostInFirestore(
mediaUrl: mediaUrl,
location: locationController.text,
description: captionController.text,
);
captionController.clear();
locationController.clear();
setState(() {
file = null;
isUploading = false;
});
}
Scaffold buildUploadForm(){
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.white70,
leading: IconButton(
icon: Icon(Icons.arrow_back,color: Colors.black,),
onPressed: clearImage,
),
title: Text(
"Caption Post",
style: TextStyle(color: Colors.black),
),
actions: <Widget>[
FlatButton(
onPressed: () => isUploading ? null : () => handleSubmit(),
child: Text(
"Post",
style: TextStyle(
color: Colors.blueAccent,
fontWeight: FontWeight.bold,
fontSize: 20.0,
),
),
)
],
),
body: ListView(
children: <Widget>[
isUploading ? linearProgress(context):Text(""),
Container(
height: 220.0,
width: MediaQuery.of(context).size.width*0.8,
child: Center(
child: AspectRatio(
aspectRatio: 16/9,
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.cover,
image: FileImage(file),
)
),
),
),
),
),
Padding(
padding: EdgeInsets.only(top:10),
),
ListTile(
leading: CircleAvatar(
backgroundImage: CachedNetworkImageProvider(widget.currentUser.photoUrl),
),
title: Container(
width: 250.0,
child: TextField(
controller: captionController,
decoration: InputDecoration(
hintText: "Write a Caption...",
border: InputBorder.none,
),
),
),
),
Divider(),
ListTile(
leading: Icon(Icons.pin_drop,color: Colors.orange,size: 35.0),
title: Container(
width: 250.0,
child: TextField(
controller: locationController,
decoration: InputDecoration(
hintText: "Where was this photo taken",
border: InputBorder.none,
),
),
),
),
Container(
width: 200.0,
height: 100.0,
alignment: Alignment.center,
child: RaisedButton.icon(
label: Text(
"Use Current Location",
style: TextStyle(color: Colors.white),
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30.0),
),
color: Colors.blue,
onPressed: () => print("Get user location"),
icon: Icon(
Icons.my_location,
color: Colors.white,
),
),
)
],
),
);
}
#override
Widget build(BuildContext context) {
return file == null ? buildSplashScreen() : buildUploadForm();
}
}
home.dart
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:fluttermedia/models/user.dart';
import 'package:fluttermedia/pages/activity_feed.dart';
import 'package:fluttermedia/pages/create_account.dart';
import 'package:fluttermedia/pages/profile.dart';
import 'package:fluttermedia/pages/search.dart';
import 'package:fluttermedia/pages/upload.dart';
import 'package:google_sign_in/google_sign_in.dart';
final GoogleSignIn googleSignIn = GoogleSignIn();
final StorageReference storageRef = FirebaseStorage.instance.ref();
final usersRef = Firestore.instance.collection('users');
final postsRef = Firestore.instance.collection('posts');
final DateTime timeStamp = DateTime.now();
User currentUser;
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
bool isAuth = false;
PageController pageController;
int pageIndex = 0;
#override
void initState() {
super.initState();
pageController = PageController();
// Detects if user signs in
googleSignIn.onCurrentUserChanged.listen((account) {
handleSignIn(account);
}, onError: (err){
print('Error sigining in: $err');
});
//Reauthenticate user when app is opened
googleSignIn.signInSilently(suppressErrors: false)
.then((account) =>
handleSignIn(account)).catchError((err){
print('Error signing in on retry: $err');
});
}
#override
Widget build(BuildContext context) {
return isAuth ? buildAuthScreen() : buildUnAuthScreen();
}
#override
void dispose(){
pageController.dispose();
super.dispose();
}
//Helper Functions
//The sign in section of the code
handleSignIn(GoogleSignInAccount account){
if(account != null){
createUserInFirestore();
setState(() {
isAuth = true;
});
}else{
setState(() {
isAuth = false;
});
}
}
login(){
googleSignIn.signIn();
}
logout(){
googleSignIn.signOut();
}
onPageChanged(int pageIndex){
setState(() {
this.pageIndex = pageIndex;
});
}
createUserInFirestore() async{
// 1) Check if user exists in users collection in database (According to id)
final GoogleSignInAccount user = googleSignIn.currentUser;
DocumentSnapshot doc = await usersRef.document(user.id).get();
if(!doc.exists){
// 2) If the user doesn't exist, take them to create account page
final username = await Navigator.push(context, MaterialPageRoute(builder: (context) => CreateAccount()));
// 3) get username from create account, use it to make new user document in users collection
usersRef.document(user.id).setData({
"id":user.id,
"username":username,
"photoUrl": user.photoUrl,
"email":user.email,
"displayName": user.displayName,
"bio":"",
"timeStamp": timeStamp,
});
doc = await usersRef.document(user.id).get();
}
currentUser = User.fromDocument(doc);
//print(currentUser);
//print(currentUser.username);
}
onTap(int pageIndex){
//This what you would use to animate in between the different screens
pageController.animateToPage(
pageIndex,
duration: Duration(milliseconds: 300),
curve: Curves.easeInOut
);
}
//UI Code
Widget buildAuthScreen() {
return Scaffold(
body: PageView(
children: <Widget>[
//Timeline(),
RaisedButton(
child: Text('Logout'),
onPressed: logout,
),
ActivityFeed(),
Upload(currentUser: currentUser),
Search(),
Profile(),
],
controller: pageController,
onPageChanged: onPageChanged,
physics: NeverScrollableScrollPhysics(),
),
bottomNavigationBar: CupertinoTabBar(
currentIndex: pageIndex,
onTap: onTap,
activeColor: Theme.of(context).primaryColor,
items: [
BottomNavigationBarItem(icon: Icon(Icons.whatshot),),
BottomNavigationBarItem(icon: Icon(Icons.notifications_active),),
BottomNavigationBarItem(icon: Icon(Icons.photo_camera, size: 34.0,),),
BottomNavigationBarItem(icon: Icon(Icons.search),),
BottomNavigationBarItem(icon: Icon(Icons.account_circle),),
],
),
);
/*return RaisedButton(
child: Text('Logout'),
onPressed: logout,
);*/
}
Scaffold buildUnAuthScreen() {
return Scaffold(
body: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topRight,
end: Alignment.bottomLeft,
colors: [
Theme.of(context).primaryColor,
Theme.of(context).accentColor,
]
)
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text('FlutterMedia',
style: TextStyle(
fontFamily: "Signatra",
fontSize: 90.0,
color: Colors.white
),
),
GestureDetector(
onTap:() => login(),
child: Container(
width: 260,
height: 60,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/images/google_signin_button.png'),
fit: BoxFit.cover,
),
),
),
)
],
),
),
);
}
}
onPressed: () => isUploading ? null : () => handleSubmit(),
Well, there's your problem. You meant to have a tertiary condition that makes onPressed call handleSubmit when isUploading is false. Instead, you have made onPressed into a function that returns a function.
To hopefully make that more clear, let's blow this function up into proper non-lambda functions and if/else blocks:
onPressed: () {
if (isUploading) {
return null;
} else {
return () {
handleUpload();
}
}
}
So consider what happens when the button is pressed. It calls the outer function, which checks isUploading. If true, the function returns null, and if false, it returns another function that, if called, calls handleUpload. So how this plays out is that onPressed will never be null (it just returns null sometimes) and handleUpload never gets called (since the inner function that is returned is never then called itself).
Remove the outer lambda and it will work:
onPressed: isUploading ? null : () => handleSubmit(),

Categories

Resources