Switching beetwen sites using flutter - flutter

Flutter don't show any error, just if _rundy = 0 page doesn't switch, 0 reaction. ZmienneClass is class for variables, not any Page which is showing on application. I guess it may be problem with Buildcontext but idk, im beginner with flutter. (ResultPage is resGamePage)
class ZmienneClass extends ChangeNotifier {
void decrementCounter(int liczba, BuildContext context) {
if (_rundy == 0) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => resGamePage(title: "Wyniki")));
void setPlayerCount({required int liczbagraczy}) {
graczepoczatkowi = liczbagraczy;}
}}}
Some resGamePage code
class resGamePage extends StatefulWidget {
const resGamePage({Key? key, value}) : super(key: key);
#override
_resGamePageState createState() => _resGamePageState();
}
class _resGamePageState extends State<resGamePage> {
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [ChangeNotifierProvider.value(value: ZmienneClass())],
child: Scaffold(

You can use push replacement command
Navigator.pushReplacement(
context,
new MaterialPageRoute(
builder: (context) => Disconnect()));
Where Disconnect is the name of your next page stless widget
This code does destroys the current activity and then it loads the next activity
You can use it to go to any page as you said in above diagram
If you are in the FirGamePage then you can go to the SecGamePage by this command by a button click or as per your UI
Hope this solution helps ;)

Related

Provider to be initialized asynchronously from `initState()` but get `could not find the correct Provider`

I develop an ad app, with a message button on the detailed view.
When the user tap on it, the chats view (stateful widget) is pushed to the screen.
The initState() is there to call the asyncInitMessages() which asynchronously fetches the chats and related message from the distant database. The asyncInitMessages() belongs to the Chats class which extends ChangeNotifier.
/// A chat conversation
class Chats extends ChangeNotifier {
/// Internal, private state of the chat.
void asyncInitMessages(
{required ClassifiedAd ad,
required String watchingUserId,
required bool isOwner}) async {
// blah blah
}
}
The ClassifiedAdMessagesViewstateful widget class implementation is as follows (snipet):
#override
void initState() {
// == Fetch conversation and messages
asyncInitMessages();
}
void asyncInitMessages() async {
// === Update all messages
try {
Provider.of<Chats>(context, listen: false).asyncInitMessages(
ad: widget.ad,
watchingUserId: widget.watchingUser!.uid,
isOwner: _isOwner);
} catch (e) {
if (mounted) {
setState(() {
_error = "$e";
_ready = true;
});
}
}
}
#override
Widget build(BuildContext context) {
// <<<<<<<<<<< The exception fires at the Consumer line right below
return Consumer<Chats>(builder: (context, chats, child) {
return Scaffold(
// ... blah blah
Finally, when running ll that, I got the exception in the build at the Consumer line:
could not find the correct Provider<chats>
Help greatly appreciated.
[UPDATED]
Here is the main (very far up from the messages screen)
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
//if (Firebase.apps.isEmpty) {
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
// } else {
// Firebase.app(); // if already initialized, use that one
// }
if (USE_DATABASE_EMULATOR) {
FirebaseDatabase.instance.useDatabaseEmulator(emulatorHost, emulatorPort);
}
runApp(RootRestorationScope(
restorationId: 'root',
child: ChangeNotifierProvider(
create: (context) => StateModel(),
child: const App())));
}
class App extends StatefulWidget {
const App({super.key});
#override
State<App> createState() => _AppState();
}
class _AppState extends State<App> {
#override
Widget build(BuildContext context) {
return PersistedAppState(
storage: const JsonFileStorage(),
child: MultiProvider(
providers: [
ChangeNotifierProvider<ThemeModel>.value(value: _themeModel),
//ChangeNotifierProvider<AuthModel>.value(value: _auth),
],
child: Consumer<ThemeModel>(
builder: (context, themeModel, child) => MaterialApp(
// blah blah
}
}
}
And the component just on top of the
/// Classified ad detail view
class ClassifiedAdDetailView extends StatefulWidget {
final User? watchingUser;
final ClassifiedAd ad;
const ClassifiedAdDetailView(
{Key? key, required this.watchingUser, required this.ad})
: super(key: key);
#override
State<ClassifiedAdDetailView> createState() => _ClassifiedAdDetailViewState();
}
class _ClassifiedAdDetailViewState extends State<ClassifiedAdDetailView>
with TickerProviderStateMixin {
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (context) => Chats(),
builder: ((context, child) => Scaffold(
// blah blah
ElevatedButton(
onPressed: () => Navigator.of(context).push(MaterialPageRoute(
builder: (context) => ClassifiedAdMessagesView(
ad: ad,
watchingUser: widget.watchingUser)));
}),
Providers must be located in the widget tree above the widget where you want to use them with Consumer or Provider.of. When you push a new route with Navigator, it won't be add the pushed route below the widget from where you push, it will add it at the same level where home of MaterialApp is located.
(I think the error message you get also states that you can't access the providers between routes.)
In general the tree will look like this if you push some routes (check it with the Flutter Widget Inspector):
MaterialApp
home
widget1
widget2
widget21
widget22
page1
widget1
widget2
page2
page3
In your code you create the provider in ClassifiedAdDetailView and then push
ClassifiedAdMessagesView from this in the onPressed method. You won't be access this provider from ClassifiedAdMessagesView because the tree will be like (simplified):
MaterialApp
home
ClassifiedAdDetailView
ClassifiedAdMessagesView
The solution is to "lift the state up" and place the provider above every widget from where you need to access it. It can be a part of your existing Multiprovider above MaterialApp but if it is too far, you need to find a proper place that is above both ClassifiedAdDetailView and ClassifiedAdMessagesView.

Flutter convert part of QuizesBloc state to QuizState

I have a List<Quiz> objects and I added these to QuizesState(Bloc is QuizesBloc) and displaying the listview. If I click on any single Quiz I want to add that particular Quiz object to another state called QuizState(Bloc is QuizBloc). How to do this?
(1) Add a selectedQuizId to your QuizesState.
(2) In your QuizesView (with the list of quizzes) add a BlocListener, listening to changes in QuizesState and if selectedQuizId is not null.
(3) navigate to a quiz route and provide selectedQuizId as an arugument
(4) create your QuizPage like this
class QuizPage extends StatelessWidget {
const QuizPage({super.key});
static Route<void> route(String? quizId) {
return MaterialPageRoute(
fullscreenDialog: true,
builder: (context) => BlocProvider(
create: (context)
{
return QuizBloc(
quizId: quizId,
repository: context.read<QuizRepository>()
)..add(QuizRequested());
},
child: const QuizPage(),
),
);
}
#override
Widget build(BuildContext context) {
return const QuizView();
}
}
(5) pick up the quizId upon initializing the QuizBloc

Is there any way to pop back to previous route by a condition in Flutter?

I'm currently doing a purchase feature on my App. Whenever free users click on a premium feature, it'll pop to the previous screen and users can now using the premium feature.
This is the current code I have:
Check on premium feature:
if (!PremiumUtils.checkLifetimePremium(user?.premiumStatus) &&
!PremiumUtils.checkSubscriptionPremium(user?.premiumExpireDate)) {
Navigator.push(context, _createUpgradeRoute());
}
If the user is a free user, display the Upgrade UI. And I used the PremiumUtils to check whether the purchase is done or not, to navigate between routes:
part of pages;
class Upgrade extends StatelessWidget {
const Upgrade({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
UserModel? user = context.watch<AppViewModel>().userModel;
return ChangeNotifierProvider(
create: (context) => UpgradeViewModel(),
child: Builder(
builder: (context) {
return Consumer<UpgradeViewModel>(
builder: (context, provider, child) {
if (PremiumUtils.checkLifetimePremium(user?.premiumStatus) ||
PremiumUtils.checkSubscriptionPremium(user?.premiumExpireDate)) {
Navigator.pop(context);
}
return the UI;
}
}
));
}
}
This obviously causing the setState() or markNeedsBuild() called during build exception. And I can't think of any way around.
Please give me some idea about this problem!
This answer solved it.
Wrap it in Future.microtask. This will schedule it to happen on the next async task cycle (i.e. after build is complete).
Future.microtask(() => Navigator.push(
context,
MaterialPageRoute(builder: (context) => LoginView())
))

How do i access a varible from another class in Flutter

I'm making my first flutter app.
it asks for some information then when you click a button it shows the information you entered on another page, I wanted to ask. How do I get a variable from another class?
so I can use the information entered on another page
It seems like you want to pass some data while navigating to another page. If I'm not wrong You should define a variable in the destination like this:
class NewPage extends StatefulWidget {
final int someInt;
NewPage({Key key, this.someInt}) : super(key: key);
#override
_NewPageState createState() => _NewPageState();
}
class _NewPageState extends State<NewPage> {
#override
Widget build(BuildContext context) {
return Container(
child: Container(child: Text("${widget.someInt}"),),
);
}
}
In the above code I passed someInt to NewPage class.
In the first page you should navigate like this:
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => NewPage(someInt: 293,),
));
put above code in the onPressed and pass the data with constructor.

Root widget not rebuilding when popping from child

I have been working on a flutter app where the user starts on a stateful widget with a ListView of items from a SQLite database. The user can tap on an item in the list which navigates to a page where the item can be modified and saved.
When Navigator.pop(context) is used, the app returns to the ListView but doesn't rebuild. The changes made do not show until I force a rebuild (hot reload)
This is a new issue in flutter 1.17.
Root view
class ItemsView extends StatefulWidget {
#override
_ItemsView State createState() => _ItemsViewState();
}
class _ItemsViewState extends State<ItemsView> {
#override
Widget build(BuildContext context) {
return FutureBuilder<List<Story>>(
future: DBProvider.db.getAllItems(),
builder: (BuildContext context, AsyncSnapshot<List<Story>> snapshot) {
if (snapshot.hasData) {
return Text(snapshot.data[0])
}
}
)
}
}
Second View
class ModifyView extends StatefulWidget {
#override
_ModifyView State createState() => _ItemsViewState();
}
class _ItemsViewState extends State<ItemsView> {
#override
Widget build(BuildContext context) {
return FutureBuilder<List<Story>>(
future: DBProvider.db.getAllItems(),
builder: (BuildContext context, AsyncSnapshot<List<Story>> snapshot) {
if (snapshot.hasData) {
return Text(snapshot.data[0])
}
}
)
}
}
How can I force the widget to reload?
You can use the Navigator's method then on which you can reload the page or do any other stuff. In below example I am using the screen A to to screen B navigation and When user navigate the from the B to A , we will refresh the view or do any other stuff like below.
From Screen A -> B
Navigator.push(
context,
MaterialPageRoute(
settings: RouteSettings(
name: B), ///// HERE "B" IS THE CLASS NAME
builder: (context) =>
B(),
),
).then((value) {
//// THIS METHOD IS ENVOKE WHEN SCREEN COME FROM B->A, YOU CAN PERFROM CAN TASK HERE
});
Inside the B screen, we need to create the constructor like below
class B extends StatefulWidget {
B () ;
#override
State<StatefulWidget> createState() {
// TODO: implement createState
return _B();
}
}
Navigation from B to A
Navigator.pop(context, 1); //// HERE WE ARE PUSHING THE ANY VALUE "1" FOR THE RETURN IN then OF CLASS "A"