0

UPDATE
I realised that the refresh is occurring due to the home_page.dart file under the StreamBuilder. This is the if statement (if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: CircularProgressIndicator());) that keeps resulting in the refresh screen and I'm not sure why. Please let me know if anyone knows why thanks!


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.

  1. main.dart - Main file with routes
  2. home_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.
  3. login_page.dart - The page to log in with GoogleAuth
  4. booking_pages.dart - Main file for the app's backbone. Consist of the scaffold which can navigate between the 2 main pages in the app
  5. book_room.dart - The page which has the Form and TextFormFields inside
  6. my_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"),
              )
            ]),
      ),
    );
  }
}
Aryan V
  • 111
  • 2
  • 9

2 Answers2

1

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

Simon Sot
  • 2,748
  • 2
  • 10
  • 23
  • Hi, after making a widget (stateful) instead of using the method as suggested by the video in the link you shared, I still face the same issue and am not sure why. The build function now should not be refreshing the entire screen but only my individual widget, so I'm not sure where the problem is. – Aryan V May 25 '22 at 04:45
0

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

Xuuan Thuc
  • 2,340
  • 1
  • 5
  • 22
  • thanks for your response. Even after I remove the `setState()` inside the method `onChanged()`, the same issue persists. Also, I am not so sure how I can extract the `TextFormField` to new `StatefulWidget()` and be able to save all my data in one place, as now I will have to access the data from a different file – Aryan V May 24 '22 at 07:37