skip to Main Content

I’m working with APIs and I want if the user is already logged in before when I open the app after the splash screen he gets redirected to the homepage directly instead of the agreement page (I want only the new logged-in users to see the agreement page).

Here’s main.dart:

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:project/firebase_options.dart';
import 'package:project/screens/home_page.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:project/screens/splash_screen.dart';
import 'package:shared_preferences/shared_preferences.dart';

// Import your theme provider class
void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);

  await dotenv.load();


}

class MyApp extends StatefulWidget {


  const MyApp({Key? key,}) : super(key: key);

  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final FirebaseMessaging _firebaseMessaging = FirebaseMessaging.instance;

  @override
  void initState() {
    super.initState();
    _configureFirebaseMessaging();

   
  }

  Future<String?> _loadGlobalId() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    return prefs.getString('globalId');
  }


  @override
  Widget build(BuildContext context) {
    final Brightness brightness = MediaQuery.of(context).platformBrightness;
    final bool isDarkMode = brightness == Brightness.dark;

    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: isDarkMode ? ThemeData.dark() : ThemeData.light(),
      home: SplashScreen()
    );
  }
}

Here’s agreement_page.dart:

class AgreementPage extends StatefulWidget {
  @override
  _AgreementPageState createState() => _AgreementPageState();
}

class _AgreementPageState extends State<AgreementPage> {
  bool _accepted = false;
  bool _loggedIn = false;
  String _code = '';
  Color _buttonColor = Colors.grey;
  String _url =
      'https://example.com/auth/example';



  @override
  void initState() {
    super.initState();

  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        automaticallyImplyLeading: false,
        backgroundColor: Color(0xff429588),
        title: Text('Terms and Conditions'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: SingleChildScrollView(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: <Widget>[
              Text(
                'End-User License Agreement',
                style: TextStyle(
                  fontSize: 24.0,
                  fontWeight: FontWeight.bold,
                ),
              ),
              SizedBox(height: 16.0),
              Text(
                ),
              SizedBox(height: 16.0),
              Row(
                children: [
                  Checkbox(
                    value: _accepted,
                    onChanged: (value) {
                      setState(() {
                        _accepted = value!;
                        _buttonColor =
                            _accepted ? Color(0xff429588) : Colors.grey;
                      });
                    },
                  ),
                  Text(
                    'I accept the terms and conditions',
                    style: TextStyle(fontSize: 16.0),
                  ),
                ],
              ),
              SizedBox(height: 16.0),
              Row(
                mainAxisAlignment: MainAxisAlignment.spaceAround,
                children: [
                  ElevatedButton(
                    onPressed: _accepted
                        ? () async {


                            // Show a webview with the url from bottom to top
                            showModalBottomSheet(
                              context: context,
                              isScrollControlled: true,
                              builder: (context) => Container(
                                height:
                                    MediaQuery.of(context).size.height * 0.9,
                                child: WebView(
                                  initialUrl: _url,
                                  javascriptMode: JavascriptMode.unrestricted,
                                  navigationDelegate: (request) {
                                    // Check if the user has logged in successfully
                                    if (request.url.startsWith(
                                        'https://exp.example.com/exp')) {
                                      setState(() {
                                        _loggedIn = true;
                                      });
                                      // Extract the code from the query parameter
                                      final uri = Uri.parse(request.url);
                                      final code = uri.queryParameters['code'];
                                      if (code != null) {
                                        setState(() {
                                          _code = code;
                                        });
                                      }
                                      // Close the webview and navigate to the homepage with the code
                                      Navigator.pop(context);
                                      Navigator.push(
                                        context,
                                        MaterialPageRoute(
                                          builder: (context) => HomePage(
                                            code:
                                                _code, // Pass the code to the homepage
                                          ),
                                        ),
                                      );
                                      return NavigationDecision.prevent;
                                    }
                                    return NavigationDecision.navigate;
                                  },
                                  gestureRecognizers: Set()
                                    ..add(
                                      Factory<VerticalDragGestureRecognizer>(
                                        () => VerticalDragGestureRecognizer(),
                                      ),
                                    ),
                                ),
                              ),
                            );
                          }
                        : null,
                    style: ButtonStyle(
                      backgroundColor:
                          MaterialStateProperty.all<Color>(_buttonColor),
                    ), // Disable the button if not accepted
                    child: Text(
                      'Accept',
                      style: TextStyle(color: Colors.white),
                    ),
                  ),
                  ElevatedButton(
                    onPressed: () {
                      // Handle the case when the user doesn't accept the agreement.
                      // You can navigate back or perform any other action.

                      // Exit the app
                      exit(0);
                    },
                    style: ButtonStyle(
                      backgroundColor:
                          MaterialStateProperty.all<Color>(Color(0xff429588)),
                    ),
                    child: Text(
                      'Don't Accept',
                      style: TextStyle(color: Colors.white),
                    ),
                  ),
                ],
              ),
            ],
          ),
        ),
      ),
    );
  }
}

Here’s home_page.dart:

class HomePage extends StatefulWidget {
  const HomePage({Key? key, this.code}) : super(key: key);

  final String? code;

  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  late Future<Map<String, dynamic>> userInfo;

  PersistentTabController _controller =
      PersistentTabController(initialIndex: 0);



  @override
  void initState() {
    super.initState();
    if (widget.code != null && widget.code!.isNotEmpty) {
      userInfo = _authenticate(widget.code!);
    }

  }

  Future<Map<String, dynamic>> _authenticate(String code) async {
    try {
      final tokenData = await AuthService.authenticate(code);
      final accessToken = tokenData['access_token'];
      final refreshToken = tokenData['refresh_token'];
      return await _fetchUserInfo(accessToken);
    } catch (e) {
      // Handle authentication error
      print('Authentication error: $e');
      throw e;
    }
  }

  Future<Map<String, dynamic>> _fetchUserInfo(String accessToken) async {
    try {
      final userInfo = await UserService.fetchUserInfo(accessToken);
      final String userName = userInfo['name'] ?? 'Unknown User';
      final String userEmail = userInfo['email'] ?? 'Unknown Email';
      final String userBirthdate = userInfo['birthdate'] ?? 'Unknown Birthdate';
      final String userGender = userInfo['gender'] ?? 'Unknown Gender';
      final String userRegion =
          userInfo['address']['region'] ?? 'Unknown Region';
      final String userPostalCode =
          userInfo['address']['postal_code'] ?? 'Unknown Postal Code';
      final String userCountry =
          userInfo['address']['country'] ?? 'Unknown Country';
      final String userPreferredUsername =
          userInfo['preferred_username'] ?? 'Unknown Preferred Username';
      final String sub = userInfo['sub'] ?? 'Unknown Global ID';

      return {
        'userName': userName,
        'userEmail': userEmail,
        'userBirthdate': userBirthdate,
        'userGender': userGender,
        'userRegion': userRegion,
        'userPostalCode': userPostalCode,
        'userCountry': userCountry,
        'userPreferredUsername': userPreferredUsername,
        'globalId': sub,
        '_getTabAccessCode': await _getTabAccessCode(sub, accessToken),
      };
    } catch (e) {
      // Handle user info fetch error
      print('Error fetching user information: $e');
      throw e;
    }
  }

  Future<Map<String, dynamic>> _getTabAccessCode(
      String globalId, String accessToken) async {
    try {
      final tabAccessCode =
          await UserService.getTabAccessCode(globalId, accessToken);
      print('Tab Access Code: $tabAccessCode');
      print(
          'Condition result: ${tabAccessCode['pid'] == tabAccessCode['doctorid']}');
      print('PID: ${tabAccessCode['pid']}');
      print('DoctorID: ${tabAccessCode['doctorid']}');

      // Get a reference to the Firestore instance
      FirebaseFirestore firestore = FirebaseFirestore.instance;

      // Determine user type based on pid and doctorid
      String userType = (tabAccessCode['pid'] == tabAccessCode['doctorid'])
          ? 'doctor'
          : 'patient';

      // Store the tab access code and user type in Firestore
      await firestore.collection('users').doc(globalId).set({
        'pid': tabAccessCode['pid'],
        'TabAccCode': tabAccessCode['TabAccCode'],
        'user_type': userType // Add this line
      });

      return {
        'pid': tabAccessCode['pid'],
        'TabAccCode': tabAccessCode['TabAccCode'],
        'user_type': userType // Add this line
      };
    } catch (e) {
      // Handle tab access code fetch error
      print('Error getting Tab Access Code: $e');
      throw e;
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      drawer: AppDrawer(userInfo: userInfo, controller: _controller),
      body: PersistentTabView(
        context,
        controller: _controller,
        screens: [
          HomeContent(userInfo: userInfo),
          FutureBuilder<Map<String, dynamic>>(
            future: userInfo,
            builder: (context, snapshot) {
              if (snapshot.connectionState == ConnectionState.waiting) {
                return Center(
                      child: SizedBox(
                        width: 50,
                        height: 50,
                        child: CircularProgressIndicator(),
                      ),
                    );
              } else if (snapshot.hasError) {
                return Text('Error: ${snapshot.error}');
              } else {
                return ConversationPage(
                  TabAccCode: snapshot.data!['_getTabAccessCode']['TabAccCode'],
                  pid: snapshot.data!['_getTabAccessCode']['pid'],
                  user_type: snapshot.data!['_getTabAccessCode']['user_type'],
                  userInfo: userInfo,
                );
              }
            },
          ),
          AppointmentPage(),
          Documents_Page(),
          MyAppsPage()
        ],
        items: [
          PersistentBottomNavBarItem(
            icon: Icon(Icons.home),
            title: ("Home"),
            activeColorPrimary: Color(0xff429588),
            inactiveColorPrimary: Colors.grey,
          ),
          PersistentBottomNavBarItem(
            icon: Icon(Icons.message),
            title: ("Messages"),
            activeColorPrimary: Color(0xff429588),
            inactiveColorPrimary: Colors.grey,
          ),
          PersistentBottomNavBarItem(
            icon: Icon(Icons.calendar_month),
            title: ("Appointments"),
            activeColorPrimary: Color(0xff429588),
            inactiveColorPrimary: Colors.grey,
          ),
          PersistentBottomNavBarItem(
            icon: Icon(Icons.edit_document),
            title: ("Documents"),
            activeColorPrimary: Color(0xff429588),
            inactiveColorPrimary: Colors.grey,
          ),
          PersistentBottomNavBarItem(
            icon: Icon(Icons.apps),
            title: ("My Apps"),
            activeColorPrimary: Color(0xff429588),
            inactiveColorPrimary: Colors.grey,
          ),
        ],
      ),
    );
  }
}

I tried doing shared preferences like this:

splash_screen.dart

void initState() {
    super.initState();
    SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersive);

    // Introduce a 2-second delay before navigating to the agreement page
    Future.delayed(Duration(seconds: 2), () async {
      // Get the instance of SharedPreferences
      SharedPreferences prefs = await SharedPreferences.getInstance();
      // Check if the user is already logged in
      bool isLoggedIn = prefs.getBool('isLoggedIn') ?? false;
      // Use Navigator to navigate based on the login state
      Navigator.of(context).pushReplacement(
        MaterialPageRoute(
            builder: (context) => isLoggedIn ? HomePage() : AgreementPage()),
      );
    });
  }

and in the agreement_page.dart where there is the user accepts:

 ElevatedButton(
                    onPressed: _accepted
                        ? () async {
                            SharedPreferences prefs =
                                await SharedPreferences.getInstance();
                            prefs.setBool('isLoggedIn',
                                true); // Set to true when logging in
                        
                            // Show a webview with the url from bottom to top
                            showModalBottomSheet(
                              context: context,
                              isScrollControlled: true,
                              builder: (context) => Container(
                                height:
                                    MediaQuery.of(context).size.height * 0.9,
                                child: WebView(
                                  initialUrl: _url,
                                  javascriptMode: JavascriptMode.unrestricted,
                                  navigationDelegate: (request) {
                                    // Check if the user has logged in successfully
                                    if (request.url.startsWith(
                                        'https://example.com')) {
                                      setState(() {
                                        _loggedIn = true;
                                      });
                                      // Extract the code from the query parameter
                                      final uri = Uri.parse(request.url);
                                      final code = uri.queryParameters['code'];
                                      if (code != null) {
                                        setState(() {
                                          _code = code;
                                        });
                                      }
                                      // Close the webview and navigate to the homepage with the code
                                      Navigator.pop(context);
                                      Navigator.push(
                                        context,
                                        MaterialPageRoute(
                                          builder: (context) => HomePage(
                                            code:
                                                _code, // Pass the code to the homepage
                                          ),
                                        ),
                                      );
                                      return NavigationDecision.prevent;
                                    }
                                    return NavigationDecision.navigate;
                                  },
                                  gestureRecognizers: Set()
                                    ..add(
                                      Factory<VerticalDragGestureRecognizer>(
                                        () => VerticalDragGestureRecognizer(),
                                      ),
                                    ),
                                ),
                              ),
                            );
                          }
                        : null,
                    style: ButtonStyle(
                      backgroundColor:
                          MaterialStateProperty.all<Color>(_buttonColor),
                    ), // Disable the button if not accepted
                    child: Text(
                      'Accept',
                      style: TextStyle(color: Colors.white),
                    ),
                  ),

but I got an error from home_page.dart:

"LateError (LateInitializationError: Field ‘userInfo’ has not been initialized.)"

If anyone could please help.

2

Answers


  1. You are facing LateInitializationError in home_page.dart because when you are navigating to HomePage from AgreementPage you are passing the code, but when you navigate to HomePage from Splash you are not passing any code and hence your userInfo not get initialized because the condition fails.

    if (widget.code != null && widget.code!.isNotEmpty) {
      userInfo = _authenticate(widget.code!);
    }
    

    In HomePage remove null operator from String? code -> String code to make the code field required, and not get stuck in the same problem again. Pass value of code in HomePage when navigating from SplashScreen.

    Hope you got the issue and this solution work for you.

    Login or Signup to reply.
  2. I think you have 2 possibilities.

    1. Do something like this in splash_screen.dart :
    void initState() {
        super.initState();
        SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersive);
    
        // Introduce a 2-second delay before navigating to the agreement page
        Future.delayed(Duration(seconds: 2), () async {
          // Get the instance of SharedPreferences
          SharedPreferences prefs = await SharedPreferences.getInstance();
          // Check if the user is already logged in
          bool isLoggedIn = await prefs.getBool('isLoggedIn') ?? false;
          var screen;
          String code = '';
          if (isLoggedIn) {
            // TODO:
            // You have to get the code here.
            // You can do some logic like you did in ElevatedButton.onPressed of agreement_page.dart.
            screen = HomePage(code: code);
          } else {
            screen = AgreementPage():
          }
          // Use Navigator to navigate based on the login state
          Navigator.of(context).pushReplacement(
            MaterialPageRoute(builder: (context) => screen)
          );
        });
      }
    

    Inside the home_page.dart, make sure code != null by doing:

    class HomePage extends StatefulWidget {
      const HomePage({Key? key, required this.code}) : super(key: key);
    
      final String code;
    
      @override
      _HomePageState createState() => _HomePageState();
    }
    
    1. Since you added null checks (??) inside _fetchUserInfo, if’s not important to show user info, you could just do this inside home_page.dart:
    class HomePage extends StatefulWidget {
      const HomePage({Key? key, this.code}) : super(key: key);
    
      final String? code;
    
      @override
      _HomePageState createState() => _HomePageState();
    }
    /* ... */
    @override
      void initState() {
        super.initState();
        userInfo = _authenticate(widget.code!);
    }
    /* ... */
    Future<Map<String, dynamic>> _fetchUserInfo(String? accessToken) async {
        try {
          var info;
          if (accessToken.code != null && accessToken!.isNotEmpty) {
            info = await UserService.fetchUserInfo(accessToken);
         
            final String sub = info['sub'] ?? 'Unknown Global ID';
    
            return {
              'userName': info['name'] ?? 'Unknown User',
              'userEmail': info['email'] ?? 'Unknown Email',
              'userBirthdate': info['birthdate'] ?? 'Unknown Birthdate',
              'userGender': info['gender'] ?? 'Unknown Gender',
              'userRegion': info['address']['region'] ?? 'Unknown Region',
              'userPostalCode': info['address']['postal_code'] ?? 'Unknown Postal Code',
              'userCountry': info['address']['country'] ?? 'Unknown Country',
              'userPreferredUsername': info['preferred_username'] ?? 'Unknown Preferred Username',
              'globalId': sub,
              '_getTabAccessCode': await _getTabAccessCode(sub, accessToken),
            };
          } else {
            info['gender'] = 'Unknown Gender';
            info['address']['region'] = 'Unknown Region';
            info['address']['postal_code'] = 'Unknown Postal Code';
            info['address']['country'] = 'Unknown Country';
            info['preferred_username'] = 'Unknown Preferred Username';
            info['sub'] = 'Unknown Global ID';
    
            return info;
          }      
        } catch (e) {
          // Handle user info fetch error
          print('Error fetching user information: $e');
          throw e;
        }
      }
    /* ... */
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search