I'm currently stuck at what I hope is a simple problem, I just tried so much that I probably just can't see the solution any longer.
I have a Landing Page that checks via a future whether the user has an active session or not (Parse Backend). I manage to make successful login and registration requests, just the screen doesn't change, meaning the future builder doesn't rebuild. When I hot reload everything works fine, but I don't manage to automatically trigger the hot reload. I user Riverpod for state management. The hasUserLogged() Method is supplied via Riverpod by an AuthBase class. I hand over the updatedUser method to the AuthScreen to trigger it on login/signUp, but it doesn't trigger a rebuild of the FutureBuilder. I thought getting an updatedUser from Server would also supply me in the next step with information whether the user has its email verified, but that's the follow up problem (but I would appreciate a pointer in the right direction how to solve the 4x4 user matrix: has token / no token & verified / unverified e-mail and redirecting to Auth / Verify E-Mail / HomePage depending on combinations..)
Anyhow, for now - how can I trigger the rebuild of the FutureBuilder upon Login/SignUp Button press in the AuthScreen?
class LandingPage2 extends StatefulWidget {
@override
_LandingPage2State createState() => _LandingPage2State();
}
class _LandingPage2State extends State<LandingPage2> {
Future<ParseUser> _updateUser() async {
final auth = context.read(authProvider);
ParseUser currentUser = await ParseUser.currentUser() as ParseUser;
if (currentUser != null) {
ParseResponse update = await currentUser.getUpdatedUser();
if (update.success) {
currentUser = update.result as ParseUser;
await auth.hasUserLogged();
setState(() {
return currentUser;
});
}
}
if (currentUser == null) {
print('null User');
}
}
/// Check if user session token is valid
Future<bool> hasUserLogged() async {
ParseUser currentUser = await ParseUser.currentUser() as ParseUser;
// return false if no user is logged in
if (currentUser == null) {
return false;
}
//Validates that the user's session token is valid
final ParseResponse parseResponse =
await ParseUser.getCurrentUserFromServer(
currentUser.get<String>('sessionToken'));
if (!parseResponse.success) {
print('invalid session. logout');
//Invalid session. Logout
await currentUser.logout();
return false;
} else {
print('login successfull');
return true;
}
}
@override
Widget build(BuildContext context) {
final auth = context.read(authProvider);
return FutureBuilder<bool>(
future: auth.hasUserLogged(),
builder: (context, snapshot) {
print('futurebuilder rebuild');
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.waiting:
return SplashScreen();
break;
default:
if (snapshot.hasData && snapshot.data) {
return HomePage();
} else {
return AuthScreen(_updateUser);
}
}
},
);
}
}
Any help is highly appreciated, struggle since hours and my head can't wrap around why it is not working :-/
Thank you @Randal Schwartz, 'watch' made it happen, after I created an AuthNotifier and StateNotifierProvider to manage the user state and depending on that user in the hasUserLogged() method.
If anyone is also struggling - that's the working version:
import 'dart:async';
import 'package:app/screens/splash_screen.dart';
import 'package:app/services/top_level_providers.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:parse_server_sdk_flutter/parse_server_sdk.dart';
import 'auth_screen.dart';
import 'home.dart';
class LandingPage2 extends ConsumerWidget {
@override
Widget build(BuildContext context, ScopedReader watch) {
final auth = watch(authProvider);
/// Check if user session token is valid
Future<bool> hasUserLogged() async {
print('hasUserLogged - Fired');
/// watch current User state -- Triggers rebuild after login!
final authNotifier = watch(authNotifierProvider.state);
final ParseUser currentUser = authNotifier;
// return false if no user is logged in
if (currentUser == null) {
print('currentUserNULL');
return false;
}
//Validates that the user's session token is valid
final ParseResponse parseResponse =
await ParseUser.getCurrentUserFromServer(
currentUser.get<String>('sessionToken'));
if (!parseResponse.success) {
print('invalid session. logout');
//Invalid session. Logout
await currentUser.logout();
return false;
} else {
print('login successfull');
return true;
}
}
return FutureBuilder<bool>(
future: hasUserLogged(),
builder: (context, snapshot) {
print('futurebuilder rebuild');
// print(snapshot.data);
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.waiting:
return SplashScreen();
break;
default:
if (snapshot.hasData && snapshot.data) {
/// Add Verify E-Mail Logic here - Another Future Builder??
return HomePage();
} else {
// _updateUser();
return AuthScreen();
}
break;
}
},
);
}
}
The Auth Notifier:
/// Auth Notifier Class
class AuthNotifier extends StateNotifier<ParseUser> {
AuthNotifier(ParseUser state) : super(state);
setCurrentUser(ParseUser user) {
state = user;
}
void clearUser() {
state = null;
}
}
And the provider:
final authNotifierProvider = StateNotifierProvider((ref) {
return AuthNotifier(null);
});
This is triggered after the active User after login / registration is received and thus triggers rebuild of hasUserLogged.
authNotifier.setCurrentUser(user);
Appreciate the help! Did cost me a lot of time... Having to switch away from firebase sucks...