I am currently making a room booking app. I have implemented the google authentication portion using SteamBuilder. However, once logged into the app, I have a Form to fill in the details - which I would eventually want to save to Cloud Firestore.
However, now I'm facing the issue that every time I click on the TextFormField widget it refreshes my entire screen. Here is the structure for my code and the code subsequently.
main.dart
- Main file with routeshome_page.dart
- Basically the file which consists of the Stream. Determines if user if logged in and whether to bring to login page or into the app.login_page.dart
- The page to log in with GoogleAuthbooking_pages.dart
- Main file for the app's backbone. Consist of the scaffold which can navigate between the 2 main pages in the appbook_room.dart
- The page which has the Form and TextFormFields insidemy_profile.dart
- Merely displays user profile from google.
To test, I even included a TextFormField inside of my_profile.dart
and realized that it also refreshes and brings me to book_room.dart
immediately.
Having read about this, it seems to be something to do with Streams but I can't seem to understand how to fix this. All my code is below. Any help is appreciated thanks!
main.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:room_booking/google_sign_in.dart';
import 'package:room_booking/pages/booking_pages.dart';
import 'package:room_booking/pages/my_profile.dart';
import 'package:room_booking/pages/book_room.dart';
import '../pages/home_page.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:firebase_core/firebase_core.dart';
import 'firebase_options.dart';
const MaterialColor primaryBlack = MaterialColor(
_blackPrimaryValue,
<int, Color>{
50: Color(0xFF000000),
100: Color(0xFF000000),
200: Color(0xFF000000),
300: Color(0xFF000000),
400: Color(0xFF000000),
500: Color(_blackPrimaryValue),
600: Color(0xFF000000),
700: Color(0xFF000000),
800: Color(0xFF000000),
900: Color(0xFF000000),
},
);
const int _blackPrimaryValue = 0xFF000000;
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
runApp(
ChangeNotifierProvider(
create: (context) => GoogleSignInProvider(),
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
MyApp({Key? key}) : super(key: key);
final storage = FirebaseStorage.instance;
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(primarySwatch: primaryBlack),
initialRoute: 'home',
routes: {
'home': (context) => HomePage(),
'bookinghome': (context) => BookingPages(),
'book': (context) => BookRoom(),
'myprofile': (context) => MyProfile(),
},
);
}
}
home_page.dart
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:room_booking/main.dart';
import 'package:room_booking/pages/booking_pages.dart';
import 'package:room_booking/pages/my_profile.dart';
import 'package:room_booking/pages/book_room.dart';
import 'package:room_booking/pages/login_page.dart';
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
double? _deviceHeight, _deviceWidth;
String? _description;
@override
Widget build(BuildContext context) {
_deviceHeight = MediaQuery.of(context).size.height;
_deviceWidth = MediaQuery.of(context).size.width;
return Scaffold(
body: StreamBuilder(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator());
} else if (snapshot.hasData) {
return BookingPages();
} else if (snapshot.hasError) {
return const Center(
child: Text("Something went wrong"),
);
} else {
return LoginPage();
}
},
),
);
}
}
login_page.dart
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:provider/provider.dart';
import 'package:room_booking/google_sign_in.dart';
import 'package:room_booking/main.dart';
class LoginPage extends StatefulWidget {
const LoginPage({Key? key}) : super(key: key);
@override
State<LoginPage> createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
double? _deviceHeight, _deviceWidth;
@override
Widget build(BuildContext context) {
_deviceHeight = MediaQuery.of(context).size.height;
_deviceWidth = MediaQuery.of(context).size.width;
return Scaffold(
backgroundColor: Colors.grey[900],
body: Container(
padding: EdgeInsets.symmetric(
horizontal: _deviceWidth! * 0.1, vertical: _deviceHeight! * 0.05),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: EdgeInsets.fromLTRB(0, _deviceHeight! * 0.2, 0, 0),
child: Column(
children: const [
Text(
"Welcome...",
style: TextStyle(
fontSize: 35,
fontWeight: FontWeight.bold,
color: Colors.white),
),
Text(
" to Room Booking",
style: TextStyle(
fontSize: 25,
fontWeight: FontWeight.bold,
color: Colors.white54),
),
],
),
),
Container(
padding: EdgeInsets.fromLTRB(
0, _deviceHeight! * 0.1, 0, _deviceHeight! * 0.2),
child: const Center(
child: Icon(
Icons.book,
color: Colors.white,
size: 70,
),
),
),
ElevatedButton.icon(
style: ElevatedButton.styleFrom(
primary: Colors.white,
onPrimary: Colors.black,
minimumSize: Size(double.infinity, 50)),
onPressed: () {
final provider =
Provider.of<GoogleSignInProvider>(context, listen: false);
provider.googleLogin();
},
icon: const FaIcon(
FontAwesomeIcons.google,
color: Colors.red,
),
label: const Text("Sign in with Google"))
],
),
),
);
}
}
bookings_page.dart
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:room_booking/google_sign_in.dart';
import 'package:room_booking/main.dart';
import 'package:room_booking/pages/book_room.dart';
import 'package:room_booking/pages/my_profile.dart';
class BookingPages extends StatefulWidget {
const BookingPages({Key? key}) : super(key: key);
@override
State<BookingPages> createState() => _BookingPagesState();
}
class _BookingPagesState extends State<BookingPages> {
int _currentPage = 0;
final List<Widget> _pages = [
BookRoom(),
MyProfile(),
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text(
"Room Booking",
),
centerTitle: true,
actions: [
TextButton(
onPressed: () {
final provider =
Provider.of<GoogleSignInProvider>(context, listen: false);
provider.logout();
},
child: const Text(
"Logout",
style: TextStyle(color: Colors.blue),
),
)
],
),
body: _pages[_currentPage],
bottomNavigationBar: _bottomNavigationBar(),
);
}
Widget _bottomNavigationBar() {
final user = FirebaseAuth.instance.currentUser!;
return BottomNavigationBar(
currentIndex: _currentPage,
unselectedItemColor: Colors.white,
selectedItemColor: Colors.blue,
backgroundColor: primaryBlack,
onTap: (_int) {
setState(
() {
_currentPage = _int;
},
);
},
items: [
const BottomNavigationBarItem(
label: "Book",
icon: Icon(Icons.book_online),
),
BottomNavigationBarItem(
label: "My Profile",
icon: ImageIcon(
NetworkImage(user.photoURL!),
),
),
],
);
}
}
book_room.dart
import 'package:flutter/material.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:path/path.dart' as path;
class BookRoom extends StatefulWidget {
const BookRoom({Key? key}) : super(key: key);
@override
State<BookRoom> createState() => _SelectRoomState();
}
class _SelectRoomState extends State<BookRoom> {
final List<Widget> _pages = [];
final Map<String, String?> _fields = {
"description": null,
"room": null,
"datetime": null,
"name": null,
"unit": null,
"purpose": null,
};
final storage = FirebaseStorage.instance;
final storageRef = FirebaseStorage.instance.ref();
//Form Key for the Form
final GlobalKey<FormState> _bookingFormKey = GlobalKey<FormState>();
double? _deviceHeight, _deviceWidth;
String? _description, _room, _datetime, _name, _unit, _purpose;
@override
Widget build(BuildContext context) {
_deviceHeight = MediaQuery.of(context).size.height;
_deviceWidth = MediaQuery.of(context).size.width;
return Scaffold(
body: _newBooking(),
);
}
Widget _newBooking() {
return Container(
padding: EdgeInsets.symmetric(
horizontal: _deviceWidth! * 0.05, vertical: _deviceHeight! * 0.05),
child: SingleChildScrollView(
child: Form(
key: _bookingFormKey,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_selectionWidget("Select Room", "room"),
_selectionWidget("Select Date/Time", "datetime"),
_selectionWidget("Name of personnel booking", "name"),
_selectionWidget("Unit", "unit"),
_selectionWidget("Purpose", "purpose"),
(_fields["room"] ?? "").isEmpty ? Text("yes") : Text("no"),
],
),
),
),
);
}
Widget _selectionWidget(description, variable) {
return Container(
height: _deviceHeight! * 0.1,
child: TextFormField(
decoration: InputDecoration(
labelText: description,
border: const OutlineInputBorder(),
errorBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.red, width: 5),
),
),
onChanged: (value) {
print(value);
setState(
() {
_fields[variable] = value;
},
);
},
),
);
}
}
my_profile.dart
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
class MyProfile extends StatefulWidget {
const MyProfile({Key? key}) : super(key: key);
@override
State<MyProfile> createState() => _MyProfileState();
}
class _MyProfileState extends State<MyProfile> {
double? _deviceHeight, _deviceWidth;
final GlobalKey<FormState> _profileFormKey = GlobalKey<FormState>();
@override
Widget build(BuildContext context) {
_deviceHeight = MediaQuery.of(context).size.height;
_deviceWidth = MediaQuery.of(context).size.width;
final user = FirebaseAuth.instance.currentUser!;
return Scaffold(
body: Container(
padding: EdgeInsets.symmetric(
horizontal: _deviceWidth! * 0.05, vertical: _deviceHeight! * 0.05),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
CircleAvatar(
radius: 40,
backgroundImage: NetworkImage(user.photoURL!),
),
Container(
width: _deviceWidth! * 0.07,
),
Text(
user.displayName!,
style: TextStyle(fontSize: 25, fontWeight: FontWeight.bold),
)
],
),
Form(
key: _profileFormKey,
child: TextFormField(initialValue: "Hi"),
)
]),
),
);
}
}
CodePudding user response:
You can't use setState()
inside method onChanged()
of TextFormField
in class BookRoom
All class BookRoom
in file book_room.dart will rebuild
Try Extract Widget TextFormField
to new StatefulWidget()
class in different file
CodePudding user response:
My humble advice is to get a good practice of using a stateless/ful widget over a function flutter would not come up with them if you just could solve problems with functions
In short: better performance and optimization
If you have time to learn more check this links: this and this
I think swapping widget functions in the root of your scaffold will be sufficient to solve refresh