Any reason why app keep stuck on splash screen? I using getx state management. If authToken not empty, it should go to main page. But onInit in controller class not calling.
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return GetMaterialApp(
initialRoute: '/splashScreen',
getPages: [
GetPage(name: '/splashScreen', page: () => SplashScreen(),binding: Bind()),
GetPage(
name: '/login', page: () => LoginPage(), binding:Bind()),
GetPage(
name: '/mainPage', page: () => MainPage(), binding:Bind())
],
debugShowCheckedModeBanner: false,
localizationsDelegates: const [
LocalizationDelegate(),
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: [
const Locale('en', ''),
const Locale('zh', ''),
],
title: 'Sample',
theme: ThemeData(
accentIconTheme: const IconThemeData.fallback().copyWith(
color: Colors.white,
),
primaryTextTheme: TextTheme(headline6: TextStyle(color: Colors.orange)),
primarySwatch: white,
primaryIconTheme: const IconThemeData.fallback().copyWith(
color: Colors.white,
),
),
// home: SplashScreen(),
);
}
}
Splash Screen
class SplashScreen extends GetView<MainPageController> {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: Container(
height: double.infinity,
width: double.infinity,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Column(
children: <Widget>[
Container(
height: 250,
width: 250,
child: Image.asset('assets/xxx.png')),
SizedBox(
height: 10,
),
],
)
],
)),
);
}
}
MainPageController
class MainPageController extends GetxController {
final con = Get.find<ProductDefectsController>();
final con1 = Get.find<ProductQualityController>();
final con2 = Get.find<ProductController>();
var tabIndex = 0;
#override
void onInit() async {
print("call onInit"); // this line not printing
// checkIsLogin();
// print("ww");
super.onInit();
}
}
Bind
class Bind extends Bindings {
Repository? _repository;
Bind() {
final _service = Get.put(Service());
final _db = Get.put(Db());
final _dao = Get.put(Dao(_db));
_repository = Get.put(Repository(_dao, _service));
}
#override
void dependencies() {
Get.lazyPut<MainPageController>(() => MainPageController());
Get.lazyPut<LoginPageController>(
() => LoginPageController(_repository!));
}
}
Edit
I tried use middlewares, but I got error
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return GetMaterialApp(
initialRoute: '/splashScreen',
getPages: [
GetPage(
name: '/splashScreen',
page: () => SplashScreen(),
binding: Bind(), middlewares: [GlobalMiddleware()]),
...
],
debugShowCheckedModeBanner: false,
localizationsDelegates: const [
....
],
);
}
}
Middleware
class GlobalMiddleware extends GetMiddleware {
final authService = Get.find<LoginPageController>();
#override
RouteSettings? redirect(String? route) {
print(authService.isLogin.value);
return authService.isLogin.value == true
? RouteSettings(
name: "/mainPage",
)
: RouteSettings(name: "/login");
}
}
Error
"LoginPageController" not found. You need to call "Get.put(LoginPageController())" or "Get.lazyPut(()=>LoginPageController())"
You need to initialize your bindings somewhere before using/finding them. A good place is to provide an instance of your binding class (in your case Bind) to the initialBinding property of GetMaterialApp:
GetMaterialApp(
...
initialBinding: Bind(),
...
)
Then you can use the Middleware approach. But the controller approach may not work just yet because the controller instance isn't used on the page/view.
Remember a controller (or any other dependency) will get initialized (thus calling the lifecycle methods like onInit) only when the controller/dependency is used/called from the page/view. Which isn't happening in your case.
you need to instantiate your controller as in the example below
class HomeBindings implements Bindings {
#override
void dependencies() {
Get.put(HomeController(influencerDataServices: Get.find(), cardsJobsServices: Get.find()));
Get.lazyPut(() => AgendaCardsController(
influencerDataServices: Get.find(), cardsJobsServices: Get.find()));
}
}
then in your route you need to call this binding, like this:
List<GetPage> routers = [
GetPage(
name: "/home",
page: () => const HomePage(),
binding: HomeBindings(),
transition: Transition.leftToRightWithFade,
opaque: false,
showCupertinoParallax: true,
)
];
getx is tightly linked to controllers and bindings, you can also try on the page's on ready instead of on init
You can delete that specific controller when you are going to that controller again by just adding these lines:
Get.delete<Yourcontroller()>();
Get.put(Yourcontroller());
In dependencies, this will solve the problem.
I cant see in this code whether you used Get.put or Get.lazyPut. Make sure that you used one of them before using a Getx controller.
Related
So I'm learning basics of bloc and I wanted to know how to change a text using a button without setstate(), this whole time ive been using setstate but I would like to know how to change a text after a button click using bloc, state, event.
This is what I have so far
Main.dart
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
BlocProvider(
create: (_) => SecscreenBloc(),
),
],
child: MaterialApp(
onGenerateRoute: Routes().onGenerateRoute,
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: SecScreen()),
);
}
}
SecScreen.dart
class SecScreen extends StatefulWidget {
const SecScreen({Key? key}) : super(key: key);
#override
State<SecScreen> createState() => _SecScreenState();
}
class _SecScreenState extends State<SecScreen> {
var numm = 1;
#override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => SecscreenBloc()..add(LoadSecscreenEvent(numm)),
child: Scaffold(
appBar: AppBar(
title: Text("Bloc Increment"),
),
body: BlocBuilder<SecscreenBloc,SecscreenState>(
builder: (context,state){
if(state is SecScreenLoadedState){
return Column(
children: [
Text("Activity: ${state.number}"),
SizedBox(height: 30),
ElevatedButton(
onPressed: () => BlocProvider.of<SecscreenBloc>(context).add(LoadSecscreenEvent(
numm
)),
child: Icon(Icons.add),
),
],
);
}
return Container(
color: Colors.red,
);
}
),
),
);
}
}
SecScreen_event.dart
abstract class SecscreenEvent extends Equatable {
const SecscreenEvent();
}
class LoadSecscreenEvent extends SecscreenEvent{
final int number;
LoadSecscreenEvent(this.number);
#override
List<Object?> get props => [number];
}
SecScreen_state.dart
part of 'secscreen_bloc.dart';
abstract class SecscreenState extends Equatable {
const SecscreenState();
}
class SecscreenInitial extends SecscreenState {
#override
List<Object> get props => [];
}
class SecScreenLoadedState extends SecscreenState{
final int number;
SecScreenLoadedState(this.number);
#override
List<Object?> get props => [number];
}
secscreen_bloc.dart
class SecscreenBloc extends Bloc<SecscreenEvent, SecscreenState> {
SecscreenBloc() : super(SecscreenInitial()) {
on<LoadSecscreenEvent>((event, emit) {
if (event is LoadSecscreenEvent){
emit(SecScreenLoadedState(event.number + 1));
}
});
}
}
I've been stuck at this for an embarssingly long time, would appreciate some help!
actually it is changed every time you press but every time the value gone to the bloc 1 and back 2 so you did not see the effection
just change the following line
onPressed: () => BlocProvider.of<SecscreenBloc>(context).add(LoadSecscreenEvent(
numm
)),
to this one :
onPressed: () => BlocProvider.of<SecscreenBloc>(context)
.add(LoadSecscreenEvent(state.number)),
I made a web app and deployed it to firebase. Let's say that the link is https://firebasewebapp. When I open the link the Sign In form shows up but when I open https://firebasewebapp/#/home I get redirected to the home page even if the user is not logged in. Is there a way to redirect the user if it's not logged in? I use Flutter 2.10.3 Stable Channel
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: options),
);
runApp(MultiProvider(providers: [
], child: const MyApp()));
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Portalul e-Radauti',
theme: ThemeData(
primarySwatch: Colors.orange,
textButtonTheme: TextButtonThemeData(
style: ButtonStyle(
backgroundColor:
MaterialStateColor.resolveWith((states) => Colors.orange),
foregroundColor:
MaterialStateColor.resolveWith((states) => Colors.white),
),
),
),
initialRoute: '/login',
routes: {
'/home': (_) => const MyHomePage(),
'/addcouncilmember': (_) => const LocalCouncilLayout(),
'/signup': (_) => const SignUp(),
'/login': (_) => const LogIn(),
'/addevent': (_) => const AddEventLayout(),
'/profile': (_) => const Profile(),
},
// home: const MyApp(),
);
}
}
The easiest way to do this would be to use Flutter's Navigator 2.0 or a package which wrap Navigator 2.0's API such as go_router or beamer.
Here's an example of how you can implement this behavior by using go_router:
router.dart
import 'package:go_router/go_router.dart';
import 'app.dart';
import 'redirection/log_in.dart';
import 'redirection/my_home_page.dart';
import 'redirection/sign_up.dart';
GoRouter routerGenerator(LoggedInStateInfo loggedInState) {
return GoRouter(
initialLocation: Routes.login,
refreshListenable: loggedInState,
redirect: (state) {
final isOnLogin = state.location == Routes.login;
final isOnSignUp = state.location == Routes.signup;
final isLoggedIn = loggedInState.isLoggedIn;
if (!isOnLogin && !isOnSignUp && !isLoggedIn) return Routes.login;
if ((isOnLogin || isOnSignUp) && isLoggedIn) return Routes.home;
return null;
},
routes: [
GoRoute(
path: Routes.home,
builder: (_, __) => const MyHomePage(),
),
GoRoute(
path: Routes.login,
builder: (_, __) => LogIn(loggedInState),
),
GoRoute(
path: Routes.signup,
builder: (_, __) => SignUp(loggedInState),
),
],
);
}
abstract class Routes {
static const home = '/home';
static const signup = '/signup';
static const login = '/login';
}
app.dart
import 'package:flutter/material.dart';
import 'router.dart';
class LoggedInStateInfo extends ChangeNotifier {
bool _isLoggedIn = false;
bool get isLoggedIn => _isLoggedIn;
void login() {
_isLoggedIn = true;
notifyListeners();
}
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final _loggedInStateInfo = LoggedInStateInfo();
late final _router = routerGenerator(_loggedInStateInfo);
#override
void dispose() {
_loggedInStateInfo.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return MaterialApp.router(
debugShowCheckedModeBanner: false,
routeInformationParser: _router.routeInformationParser,
routerDelegate: _router.routerDelegate,
);
}
}
With this code you only need to update the value of _isLoggedIn inside the LoggedInStateInfo and notify the listeners to access the HomePage, otherwise you will only have access to the LogIn and SignUp pages even when you manually change the URL.
Bonus
LogIn page code
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import '../app.dart';
import '../router.dart';
class LogIn extends StatelessWidget {
final LoggedInStateInfo loggedInStateInfo;
const LogIn(this.loggedInStateInfo, {Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('LogIn')),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
ElevatedButton(
onPressed: loggedInStateInfo.login,
child: const Text('Log In'),
),
const SizedBox(height: 16),
ElevatedButton(
onPressed: () => context.push(Routes.signup),
child: const Text('Sign Up'),
),
],
),
),
);
}
}
SignUp page code
import 'package:flutter/material.dart';
import '../app.dart';
class SignUp extends StatelessWidget {
final LoggedInStateInfo loggedInStateInfo;
const SignUp(this.loggedInStateInfo, {Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('SignUp')),
body: Center(
child: ElevatedButton(
onPressed: loggedInStateInfo.login,
child: const Text('Sign Up'),
),
),
);
}
}
I want to implement GetX binding methods, and as result, I got this error:
════════ Exception caught by widgets library ═══════════════════════════════════
The following message was thrown building MyApp(dirty):
"UserController" not found. You need to call "Get.put(UserController())" or "Get.lazyPut(()=>UserController())"
The relevant error-causing widget was
MyApp
lib/main.dart:9
main.dart
import 'package:donirajkrv/views/welcome.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import './router/index.dart';
import './bindings/user_binding.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return GetMaterialApp(
initialBinding: UserBinding(),
home: const Scaffold(
backgroundColor: Color.fromRGBO(244, 248, 252, 1),
body: SafeArea(child: WelcomePage()),
),
getPages: [...routeList],
debugShowCheckedModeBanner: false,
theme: ThemeData(
primaryColor: const Color(0XFFFB6394),
appBarTheme: const AppBarTheme(
systemOverlayStyle: SystemUiOverlayStyle.dark,
),
),
);
}
}
How main works:
void main() {
Get.put<UserController>(UserController());
runApp(const MyApp());
}
user_binding.dart
import 'package:get/get.dart';
import 'package:donirajkrv/controllers/user_controller.dart';
class UserBinding implements Bindings {
#override
void dependencies() {
Get.put(() => UserController());
}
}
Routelist:
import 'package:get/get.dart';
import '../views/welcome.dart';
import '../views/login.dart';
import '../views/register.dart';
import '../views/home_page.dart';
import '../middlewares/auth_middleware.dart';
import '../middlewares/back_to_home_middleware.dart';
// Routes path
import '../routes/index.dart';
List routeList = [
GetPage(
name: '/${Routes.WELCOME_PAGE}',
page: () => const WelcomePage(),
middlewares: [BackToHomeMiddleware()]),
GetPage(
name: '/${Routes.LOGIN_PAGE}',
page: () => const Login(),
middlewares: [BackToHomeMiddleware()]),
GetPage(
name: '/${Routes.REGISTER_PAGE}',
page: () => const Register(),
middlewares: [BackToHomeMiddleware()]),
GetPage(
name: '/${Routes.HOME_PAGE}',
page: () => const HomePage(),
middlewares: [AuthMiddleware()])
];
i have added the detail code for binding controller and increment function so try using this, it will definitely work
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return GetMaterialApp(
initialBinding: UserBinding(),
getPages: [...routeList],
initialRoute: RouteNames.welcomePage,
home: const Scaffold(
backgroundColor: Color.fromRGBO(244, 248, 252, 1),
),
debugShowCheckedModeBanner: false,
theme: ThemeData(
primaryColor: const Color(0XFFFB6394),
appBarTheme: const AppBarTheme(
systemOverlayStyle: SystemUiOverlayStyle.dark,
),
),
);
}
}
class UserController extends GetxController {
var i = 0.obs;
void increment(){
i++;
}
}
class RouteNames {
static String welcomePage = "/welcomePage";
}
List routeList = [
GetPage(
name: '/${RouteNames.welcomePage}',
page: () => WelcomePage(),
),
];
//here use binding like this
class UserBinding implements Bindings {
#override
void dependencies() {
Get.put<UserController>(UserController(), permanent: true);
}
}
class WelcomePage extends StatelessWidget {
WelcomePage({Key? key}) : super(key: key);
// final userController = Get.put(UserController());
final userController = Get.find<UserController>();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
),
body: Column(
children: [
Obx(() => Text(userController.i.value.toString(),
style: const TextStyle(
fontSize: 25,
color: Colors.blueAccent
),),),
ElevatedButton(onPressed: (){
userController.increment();
}, child: const Text("Button")),
],
),
);
}
}
you should make a simple change
Instead of
GetMaterialApp(
initialBinding: BindingsBuilder(() {
Get.put(UserBinding());
})...
use
initialBinding: UserBinding())...
GetMaterialApp(
initialBinding: UserBinding())...
In the user_binding.dart file you can initiate every controller that your app uses.
and then you can use it by simply declare a variable like this
UserController controller = Get.find();
//or like this:
final controller = Get.find<UserController>();
//I haven't tested the second one, but it should work.
Hope it works :)
You can also follow the example below:
https://github.com/Prosa/Flutter-GetX-Bindings-Example
I am trying to understand how guarding works, my setup is as follows:
router
#AdaptiveAutoRouter(
replaceInRouteName: 'Page,Route',
routes: <AutoRoute>[
AutoRoute(
page: LoginPage,
initial: true,
path: '/login',
),
AutoRoute(page: HomePage, path: '/home', guards: [AuthGuard]),
],
)
class $AppRouter {}
guard
class AuthGuard extends AutoRouteGuard {
//from context.watch<AuthService>().isAuthenticated
AuthGuard({required this.isAuthenticated});
final bool isAuthenticated;
#override
void onNavigation(NavigationResolver resolver, StackRouter router) {
if (isAuthenticated) {
resolver.next(isAuthenticated);
} else {
router.push(LoginRoute());
router.popForced();
// resolver.next();
}
}
}
service
class AuthService extends ChangeNotifier {
bool isAuthenticated = false;
login() {
isAuthenticated = true;
notifyListeners();
}
logout() {
isAuthenticated = false;
notifyListeners();
}
}
screens
class LoginPage extends StatelessWidget {
const LoginPage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Login Page'),
),
body: Center(
child: Column(
children: [
ElevatedButton(
onPressed: () {
context.read<AuthService>().login();
context.pushRoute(HomeRoute());
},
child: Text('Authenticate Me')),
ElevatedButton(
onPressed: () {
context.pushRoute(HomeRoute());
},
child: Text('Go Home')),
],
),
),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home Page'),
),
body: Center(
child: ElevatedButton(
onPressed: () {
context.read<AuthService>().logout();
},
child: Text('Uauthenticate Me')),
),
);
}
}
Now clicking Go Home button prevents me from navigating to the home page which is correct, however when I click Authenticate Me button, it does not route me to the HomeRoute but instead I get a blank screen while the path still shows /login.
Sorry I don't see where you pass your argument isAuthenticated, maybe this is the issue ? I've seen you gave up auto_route in the comment, I post this answer for you or those who face issue to handle guard on provider.
Provider
You can get the context to get your provider from your guard.
#override
void onNavigation(NavigationResolver resolver, StackRouter router) async {
final context = router.navigatorKey.currentContext;
context.read< AuthService>()
// Use your provider
}
When i invoke the loadingDelete method upon deleting a post where the Navigator.push.. takes place, i am directed to the Profile page but with my bottom navigation bar empty (appearing empty where icons(content) are blank).
I keep on encountering this problem when i either upload or delete a post..I tried replacing scaffold with MaterialApp but did't work...
This is where my loadingDelete method resides:
class PostStateless extends StatelessWidget {
final Post post2;
PostStateless(this.post2);
#override
Widget build(BuildContext context) {
print("REACHED HERE BEG "+post2.toString());
return new Scaffold(
resizeToAvoidBottomInset: false,
body:PostPage(post2),
);
}
}
class PostPage extends StatefulWidget {
final Post post2;
PostPage(this.post2);
#override
PostPageState createState() => new PostPageState(post2);
}
class PostPageState extends State<PostPage> with TickerProviderStateMixin {
...
..
loadingDelete()
{
if(!loadingDeletePost)
return Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("lib/assets/BackToEarth.jpg"),
fit: BoxFit.cover,
),
),
child: Center(
child: Row(
mainAxisSize: MainAxisSize.min, //centered things bil nos
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
CircularProgressIndicator(
valueColor: new AlwaysStoppedAnimation<Color>(Colors.black),
)
]),
/* add child content here */
));
else {
Navigator.of(context).pushAndRemoveUntil(MaterialPageRoute(builder: (context) =>
Profile()), (Route<dynamic> route) => false);
//Navigator.push alone redirects me to the profile page with blank nav bar plus arrow back
visible in my app bar(Worse).
}
}
....
}
This is my Profile page structure:
class Profile extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: ProfilePage(),
);
}
}
class ProfilePage extends StatefulWidget {
#override
_ProfilePageState createState() => new _ProfilePageState();
}
class _ProfilePageState extends State<ProfilePage> {
...
...
}
This is the structure of my global bottom nav bar which resides in my mainn dart file under MaterialApp Widget:
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Instagram',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
ManageUserModel user;
class _MyHomePageState extends State<MyHomePage> {
ApiService apiService = ApiService();
List<Widget> pages = [
HomePage(),
SearchPage(),
Post(),
NotificationsPage(),
ProfilePage()
];
saveVariable(ManageUserModel user) async {
// save variable
SharedPreferences sharedUser = await SharedPreferences.getInstance();
String userSt=toJson(user);
print("USERST: "+userSt);
sharedUser.setString('user', userSt);
}
#override
void initState() {
apiService.getUsers("beeso").then((result) {
setState(() {
user = result;
print("USERRRR" +user.toString());
saveVariable(user);
});
});
super.initState();
}
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: 5,
initialIndex: 0,
child: Scaffold(
body: TabBarView(
children: pages,
),
bottomNavigationBar:
Container(
margin: EdgeInsets.only(bottom: 20),
child: new TabBar(
tabs: [
Tab(
icon: Icon(Icons.home),
),
Tab(
icon: Icon(Icons.search),
),
Tab(
icon: Icon(Icons.add),
),
Tab(
icon: Icon(Icons.favorite),
),
Tab(
icon: Icon(Icons.perm_identity),
),
],
unselectedLabelColor: Colors.black,
labelColor: Colors.blue,
indicatorColor: Colors.transparent,
),
),
),
);
}
}
Any help is appreciated!!
Change the navigation to the following code:
Navigator.of(context).popUntil((route) => route.isFirst);