i'm working on a app. after payment is successful i want to navigate to another page.
Here is the code of my app payment method in the
void handlerPaymentSuccess() { Navigator.push(context, MaterialPageRoute(builder: (context) => Itemsbuy()));
i coded this to navigate that page but after payment is success this is not showing,
but after payment done its showing only payment successful from the razorpay but its not showing my page which i navigated. after payment success it is redirecting to the second route not redirecting to the Itemsbuy();
class SecondRoute extends StatefulWidget {
#override
_SecondRouteState createState() => _SecondRouteState();}
class _SecondRouteState extends State<SecondRoute> {
Razorpay razorpay;
TextEditingController textEditingController = new TextEditingController();
#override
void initState() {
razorpay = new Razorpay();
razorpay.on(Razorpay.EVENT_PAYMENT_SUCCESS, handlerPaymentSuccess);
razorpay.on(Razorpay.EVENT_PAYMENT_ERROR, handlerPaymentError);
razorpay.on(Razorpay.EVENT_EXTERNAL_WALLET, handlerExternalWallet);
super.initState(); }
void handlerPaymentSuccess() {
Navigator.push(context, MaterialPageRoute(builder: (context) => Itemsbuy()));//Items purchased}
this is the navigation that i want to push
void handlerPaymentError()
{
print('error'); }
void handlerExternalWallet()
#override
void dispose()
{
super.dispose();
razorpay.clear(); }
var options = {
"key": "empty",
"amount": empty,
"name": 'empty',
"Description": 'empty',
};
try {
razorpay.open(options);
} catch (e) {
debugPrint('error');
}}
thank you
Use the GetX package for navigation instead of Navigator.of(context)
Example:
void handlerPaymentSuccess() {
Get.to(Itemsbuy());
}
Also make sure to use GetMaterialApp instead of MaterialApp like this:
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return GetMaterialApp(
home: SplashScreen(),
color: violet,
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.deepPurple,
).copyWith(textTheme: GoogleFonts.montserratTextTheme()),
);
}
}
It should work.
class _Payment extends State {
bool paymentDone = false;
#override
Widget build(BuildContext context) {
if (paymentDone == true) {
return NewPage();
}
else{
return CurrentPage();
}
}
void _handlePaymentSuccess(PaymentSuccessResponse response) async {
Fluttertoast.showToast(msg: "SUCCESS: " + response.paymentId, timeInSecForIosWeb: 4);
setState(() {
paymentDone = true;
);}
}
}
Related
I am using flutter with the supabase package. It sends a Stream of authentication events that I can listen to.
I just can't figure out how to redirect to a completely new page on such an auth event. For example, when the app receives a passwordRecovery event, then I want to drop the whole navigator stack and just show the Reset Password page. When the app receives a signedIn event, I want to drop the navigator stack and just show the HomePage.
This is what I am currently trying:
class AuthApp extends StatefulWidget {
const AuthApp({super.key});
#override
State<AuthApp> createState() => _AuthAppState();
}
class _AuthAppState extends State<AuthApp> {
late final StreamSubscription<AuthState> _authStateSubscription;
bool _isLoggedIn = supabaseClient.auth.currentSession != null;
bool _resettingPassword = false;
#override
void initState() {
super.initState();
_setupAuthStateSubscription();
}
void _setupAuthStateSubscription() {
print('Setting up auth state subscription');
_authStateSubscription =
supabaseClient.auth.onAuthStateChange.listen((data) {
final AuthChangeEvent event = data.event;
final Session? session = data.session;
print("Auth event: ${event.toString()}");
setState(() {
_currentUser = session?.user;
_isLoggedIn = session != null;
if (event == AuthChangeEvent.passwordRecovery) {
_resettingPassword = true;
}
});
if (event == AuthChangeEvent.signedOut ||
event == AuthChangeEvent.signedIn ||
event == AuthChangeEvent.passwordRecovery) {
print('clearing navigator stack');
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(builder: (context) => widget),
(route) => false,
);
});
}
Widget getNextPage() {
if (_resettingPassword) {
return const ResetPasswordScreen();
} else if (_isLoggedIn) {
return const MainApp();
} else {
return const WelcomeScreen();
}
}
#override
void dispose() {
_authStateSubscription.cancel();
super.dispose();
}
#override
Widget build(BuildContext context) {
return getNextPage();
}
}
Login does work, but for some reason on the password recovery event, the widget is disposed and I see the Home Page.
widget variable will always contain the initial state of the widget. You can verify this with the following code.
class HomePage extends StatefulWidget {
const HomePage({super.key});
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
String _test = 'before presee';
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ElevatedButton(
onPressed: () {
setState(() {
_test = 'after press';
});
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(builder: (context) => widget),
(route) => false);
},
child: Text(_test)),
),
);
}
}
What might be better is to just have different widgets for login page or password recovery page and navigate to those pages depending what the event is.
if(event == AuthChangeEvent.passwordRecovery) {
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(builder: (context) =>PasswordRecoveryPage()),
(route) => false);
} else {
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(builder: (context) =>LoginPage()),
(route) => false);
}
I want to make a small login application. When entering the application, I want to inquire whether the user has a token code or not on the splash screen. How can do this? thank you for help.
main.dart file
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: SplashScreen(),
);
}
}
My splash screen.
I want to know if the user has a token or not
class SplashScreen extends StatefulWidget {
#override
_SplashScreenState createState() => _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen> {
#override
void initState() {
super.initState();
loginControl();
}
// ignore: missing_return
Future<bool> loginControl() async {
bool status = AuthController.isLoginUser() as bool;
print(status);
if (status) {
Navigator.of(context).pushReplacement(
MaterialPageRoute(builder: (BuildContext context) => HomeScreen()));
} else {
Navigator.of(context).pushReplacement(
MaterialPageRoute(builder: (BuildContext context) => LoginScreen()));
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Text('welcome my app'),
),
);
}
}
my auth controller like this;
class AuthController {
static Future<bool> isLoginUser() async {
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
String token = sharedPreferences.getString("token");
if (token == null) {
return false;
} else {
return true;
}
}
}
Your isLoginUser is actually returning a Future<bool> means that it returns a Future that will later resolve to a bool value.
So, when you use it like this in your loginControl,
bool status = AuthController.isLoginUser() as bool;
AuthController.isLoginUser() return Future<bool> and it can't be directly converted to a bool using as bool.
Instead you should await that Future to resolve, like this.
bool status = await AuthController.isLoginUser(); // This will work.
Now, your code will pause at this line, until it gets a return value from isLoginUser and then resume to next line with status being an actual bool value. i.e., true or false.
Hy here everyone. I am new to flutter and i want to check if User is SignedIn. If so the user navigate to HomeScreen else SplashScreen.
Here is my main.dart
void main() async{
runApp(MyApp());
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Instant Tasker',
theme: theme(),
initialRoute: SplashScreen.routeName,
routes: routes,
);
}
}
Here is Splash Screen
class SplashScreen extends StatefulWidget {
static String routeName = "/splash";
#override
_SplashScreenState createState() => _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen> {
startTime() async {
var _duration = new Duration(seconds: 2);
return new Timer(_duration, navigationPage);
}
void navigationPage() {
var auth = FirebaseAuth.instance;
// ignore: deprecated_member_use
auth.onAuthStateChanged.listen((user) {
if (user != null) {
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(builder: (context) => MainScreen()),
(Route<dynamic> route) => false);
} else {}
});
}
#override
void initState() {
super.initState();
startTime();
}
#override
Widget build(BuildContext context) {
SizeConfig().init(context);
return Scaffold(
body: Body()
);
}
}
However i achieved to check user at splash screen but it stays at splash screen to check user then move to HomeScreen which doesn't seems to be good.
Or can anybody suggest how to show CircularProgressIndicator instead of Splash Screen body when it is checking for user
You can achieve it using StreamProvder
Implementation
Steps
Create a CustomUser Data model.
class CustomUser {
final String userId;
CustomUser({this.userId});
}
Create a class named FirebaseAuthService and create a stream to listen to Firebase AuthStateChanges
import 'package:firebase_auth/firebase_auth.dart';
class FirebaseAuthService {
final FirebaseAuth auth = FirebaseAuth.instance;
// create user obj based on firebase user
CustomUser _userFromFirebaseUser(User user) {
return user != null ? CustomUser(userId: user.uid) : null;
}
// auth change user stream
//Required stream
Stream<CustomUser> get user {
return auth.authStateChanges().map(_userFromFirebaseUser);
}
}
}
Add a StreamProvider on top of the widget tree where you want to check for the AuthState.
void main() async{
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return StreamProvider<CustomUser>.value(
value: FirebaseAuthService().user,
child: MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Instant Tasker',
theme: theme(),
initialRoute: SplashScreen.routeName,
routes: routes,
)
);
}
}
Create a Wrapper and return SplashScreen or HomeScreen based on AuthState.
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class Wrapper extends StatefulWidget {
#override
_WrapperState createState() => _WrapperState();
}
class _WrapperState extends State<Wrapper> {
#override
Widget build(BuildContext context) {
final user = Provider.of<CustomUser>(context);
if (user == null) {
return SplashScreen();
}
return HomeScreen();
}
}
Now you can use final user = Provider.of<CustomUser>(context);
in the widget tree to check if the user is null.
https://www.youtube.com/watch?v=z05m8nlPRxk&list=PL4cUxeGkcC9j--TKIdkb3ISfRbJeJYQwC&index=3
We moved from Page1 to Page2 but now from Page2 we move back again to Page1 like this:
Navigator.of(context).pop();
How can we detect on Page1 that we went back?
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => NextPage(),
),
).then((_){
// Here you will get callback after coming back from NextPage()
// Do your code here
});
In your Page1, When you push Page2 wait for it to pop
Future<void> _goToPage2() async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Page2(),
),
);
print("Page2 is popped");
}
Another solution, which is more verbose but also more efficient if you push a lot of Routes from the same Widget, would be to create your own NavigatorObserver.
1- Create your NavigatorObserver
final routeObserver = MyRouteObserver();
class MyRouteObserver extends NavigatorObserver {
final Set<RouteAware> _listeners = <RouteAware>{};
void subscribe(RouteAware routeAware) {
_listeners.add(routeAware);
}
void unsubscribe(RouteAware routeAware) {
_listeners.remove(routeAware);
}
#override
void didPop(Route<dynamic> route, Route<dynamic>? previousRoute) {
for (var listener in _listeners) {
listener.didPop();
}
}
}
2- Add it to your MaterialApp
return MaterialApp(
navigatorObservers: [routeObserver],
...
3- Implement RouteAware in the Widget where you want to listen to Navigation events, and subscribe/unsubscribe to your routeObserver
class _TablePageState extends State<TablePage> implements RouteAware {
#override
void initState() {
super.initState();
routeObserver.subscribe(this);
}
#override
Widget build(BuildContext context) {
return Container();
}
#override
void dispose() {
routeObserver.unsubscribe(this);
super.dispose();
}
#override
void didPop() {
//This method will be called from your observer
}
#override
void didPopNext() {}
#override
void didPush() {}
#override
void didPushNext() {}
}
I am trying to keep the user of my app logged in until they logout. This is an app that accesses an api for authentication. I want to keep the user logged in using the setState method and not the token authentication method. I am able to successfully login but when I close and open the app again, I have to re-login.
Below are the files with the related code using the setState function. I am unable to find my error.
main.dart:
void main() => runApp(new MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => new _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: "Splash and Token Authentication",
routes: <String, WidgetBuilder>{
"/HomeScreen": (BuildContext context) => HomeScreen(),
"/LoginScreen": (BuildContext context) => LoginScreen(),
},
//state variable is in loginScreen.dart file
home: ((state == loginState.LOGGED_IN)? HomeScreen():LoginScreen())
);
}
#override
void initState() {
super.initState();
}
}
loginScreen.dart:
import ...
enum loginState{ LOGGED_IN, LOGGED_OUT}
loginState state;
const URL = "http://www.google.com";
class LoginScreen extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return new LoginScreenState();
}
}
class LoginScreenState extends State<LoginScreen> {
final TextEditingController _userNameController = TextEditingController();
final TextEditingController _passwordController = TextEditingController();
String _welcomeString = "";
Future launchURL(String url) async {
if(await canLaunch(url)) {
await launch(url, forceSafariVC: true, forceWebView: true);
} else {
showDialogSingleButton(context, "Unable to reach your website.", "Currently unable to reach the website $URL. Please try again at a later time.", "OK");
}
}
#override
void initState() {
super.initState();
_saveCurrentRoute("/LoginScreen");
}
_saveCurrentRoute(String lastRoute) async {
SharedPreferences preferences = await SharedPreferences.getInstance();
await preferences.setString('LastScreenRoute', lastRoute);
}
}
#override
Widget build(BuildContext context) {
//LoginScreen UI
}
}
homeScreen.dart:
import ...
class HomeScreen extends StatefulWidget {
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
#override
void initState() {
super.initState();
_saveLoginState();
_saveCurrentRoute("/HomeScreen");
}
_saveCurrentRoute(String lastRoute) async {
SharedPreferences preferences = await SharedPreferences.getInstance();
await preferences.setString('LastScreenRoute', lastRoute);
}
Future<void> _saveLoginState() async{
setState(() {
state = loginState.LOGGED_IN;
});
}
#override
Widget build(BuildContext context) {
//HomeScreen UI
}
use onGenerateRoute inside your MaterialApp
Here you can set initialRoute, after log in change SharedPreferences to your loginScreen route. and then you can get route when app is started.
#override
Widget build(BuildContext context) {
String initialRoute = '/';
return MaterialApp(
theme: _themeData,
onGenerateRoute: (s) => _getCurrentRoute(s),
initialRoute: initialRoute,
);
}
_getCurrentRoute(RouteSettings settings) {
print(settings.arguments);
switch (settings.name) {
case '/':
return MaterialPageRoute(
builder: (context) => PageRouter(
child: LogInPage(),
isSearchBar: false,
));
case '/home':
return MaterialPageRoute(
builder: (context) => PageRouter(
child: Home(),
isSearchBar: true,
));
case '/plp_page':
return MaterialPageRoute(
builder: (context) => PageRouter(
child: PlpPage(),
isSearchBar: false,
));
case '/pdp_page':
return MaterialPageRoute(builder: (context) => PdpPage());
case '/cart_page':
return MaterialPageRoute(
builder: (context) => PageRouter(
child: CartPage(),
isSearchBar: false,
));
}
}
You are looking for the shared_preferences package.
You need to Save your Data into Shared Preference when user logs in, and when user log out you need to clear all the Shared Preference.
While When user opens up app again you need to check if the Shared Preference has data of user or not.
Sample Code:
//Initialise SharedPreferences
SharedPreferences prefs = await SharedPreferences.getInstance();
//set some value in it.
//In your case your user data like some id, email or anything
await prefs.setInt('key', value);
//Getting data from preference.
final someName = prefs.getInt('key')