Calling a Future from another file in Flutter - flutter

I'm trying to get data to a different .dart file from Future.
For doing this, I created a class after Future code.
The code in pageone.dart:
class Popups extends StatefulWidget {
#override
_PopupsState createState() => _PopupsState();
}
class _PopupsState extends State<Popups> {
Future oyuncuSec() async {
await showDialog(
context: context,
...
...
}
}
class UserService {
oyuncuSec() {}
}
The code in pagetwo.dart, where I would like to call the same Future code:
import 'package:myappname/pageone.dart';
.
.
UserService userService = UserService();
.
.
RaisedButton(
onPressed: () => userService.oyuncuSec(), child: Text('Futbolcu Resmi'),),
But, when I run the page, and press on the RaisedButton (Futbolcu Resmi), it does not show up the pop-up. I'm stick on this for days. Please help me.

I see that you have created a separate class with the function definition inside it, that's the right way of doing it!
You must be missing something minimal in your code, make sure you define the class and the function as follows:
Let's say you are writing the class which has the function in a file called data.dart.
data.dart should look like this:
Class DataSource {
Future oyuncuSec() async {
await showDialog(
context: context,
...
...
}
}
Now let's say you want to use this function in a file called x.dart, this goes as follows:
in x.dart (which has a stateful widget), outside the build function:
var dataSource = new Datasource();
//an example function:
getData() async {
await dataSource.oyuncuSec(); //use a .then() in the end if the function oyuncuSec returns something and you want to do something with the result...
}
Edit: If you don't want oyuncuSec to return anything and just make a popup, there is no need to set its return type as Future. Just define it as void oyuncuSec() {//code for popup}

Related

Using deferred libraries with variables

Sorry in advance I am a beginner and my English is approximate.
I don't know if what I'm doing is correct or not so sorry (again) if this sounds stupid to you.
I try to recover the contents of certain files only when I need them.
I think it's good for optimizing my dart/flutter app and reducing loading times.
So
So I have a list of files coded like this :
N101aze.dart which contains a Map called N101aze
N101qsd.dart which contains a List called N101qsd
N101wxc.dart which contains a List called N101wxc
...
In the same way I have :
N102aze.dart which contains a Map called N102aze
N102qsd.dart which contains a List called N102qsd
N102wxc.dart which contains a List called N102wxc
...
etc...
Each time I have another file called and coded like that :
N101.dart
export "path[...]/N101aze.dart";
export "path[...]/N101qsd.dart";
export "path[...]/N101wxc.dart";
...
Now in a file I want to make a Deferred loading like that :
import "path[...]/N101.dart" deferred as N101; //I know lowercase is better
I load the library when I want by using
greet() async {
await N101.loadLibrary();
}
and later I can call my maps and lists by using
N101.N101aze
N101.N101qsd
It's working perfectly when I use the names listed above.
Now, what I really want is to use a key (called kkey here) to call the library I want when I call onPressed on ElevatedButton :
import 'package:flutter/material.dart';
import 'package:my_app/Models/SetColor.dart';
import "path[...]/N101.dart" deferred as N101; //I know lowercase is better
import "path[...]/N102.dart" deferred as N102;
import "path[...]/N103.dart" deferred as N103;
...
class CustomButton extends StatefulWidget {
const CustomButton({
required this.kkey,
}) : super(key: key);
final String kkey;
#override
State<CustomButton> createState() => _CustomButtonState();
}
class _CustomButtonState extends State<CustomButton> {
Future<void> greet(thekey) async {
await thekey.loadLibrary();
}
#override
Widget build(BuildContext context) {
return ElevatedButton(
child: Text(
widget.kkey
),
onPressed: () async {
await greet(widget.kkey); //it's not working beacause kkey type is String
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => LoadingParts(
part1: // here I want N101.N101aze when kkey="N101" so I want something like kkey.kkeyaze
part2: // here I want N101.N101qsd when kkey="N101" so I want something like kkey.kkeyqsd
...
Note :
I "simplified" the code to keep only the essentials
part1 is a Map and part2 is a List
For the greet function, I think I understand it doesn't work because N101, N102, N103... have no type and my kkey is the type of String but I don't know what is possible to do...
To invoke my maps and my lists, I have no idea what to do... Especially when I want to concatenate kkey with aze (for example).
I know I can use Switch Case Statement which looks at all characters from kkey to return, for example "N101.loadlibrary()" and "N101.N101.aze" but the number of "Switch" and "Case" is too big to be worth it and the number of possibilities may increase as the application grows.
I hope you will understand my problem and I hope it's not too stupid, I'm learning^^.
Thank you for your attention! Bye!
Unfortunately, there is no way to do it dynamically this way i.e. getting a declaration by name. Although Dart is a static language that supports reflection, flutter does not by default. In Flutter the mirrors package is disabled in favour of static optimization. There is also reflectable but it has limitations where it's not possible to reflect a module for example.
So, the way to fix it is to use static code too to load the deferred libs like the following.
On each NXXX.dart file, where XXX is 101, 102, 103 etc., declare the same map. For example, in N101.dart it's going to be like this:
// Create a map with all structures needed
final nmap = {
'aze': N101aze,
'qsd': N101qsd,
'wxc': N101wxc,
};
And then the usage is going to be like this:
class CustomButton extends StatefulWidget {
const CustomButton({
Key? key,
required this.kkey,
}) : super(key: key);
final String kkey;
#override
State<CustomButton> createState() => _CustomButtonState();
}
class _CustomButtonState extends State<CustomButton> {
Future<Map<String, Object>> greet(String thekey) async {
// Load the deferred module and return the structures
switch (thekey) {
case 'N101':
await N101.loadLibrary();
return N101.nmap;
case 'N102':
await N102.loadLibrary();
return N102.nmap;
case 'N103':
await N103.loadLibrary();
return N103.nmap;
default:
assert(false);
throw Exception('$thekey not mapped');
}
}
#override
Widget build(BuildContext context) {
return ElevatedButton(
child: Text(widget.kkey),
onPressed: () async {
// Get the common `nmap` from `greet` by `kkey`
final nmap = await greet(widget.kkey);
if (mounted) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => LoadingParts(
// Use the `nmap` by name
part1: nmap['aze']! as Map,
part2: nmap['qsd']! as List,
part3: nmap['wxc']! as List,
),
),
);
}
},
);
}
}

Retry Future<void> API call on timeout

I've implemented on TimeoutException on each API calls. Initially, it was just showing a simple bottomsheet dialog that is being called from a Utils class which is accessible globally so that I don't have to paste the Widget in each API call and just call the function in the Utils class with a String message parameter.
Like:
on TimeoutException {
Utils().showError("login timeout");
}
Now to improve the UX, I added a "retry" button inside the bottomsheet dialog for the purpose of retrying/recalling the function.
I've created dynamic widgets that is reusable across the project and receives a Function and it works.
However, my issue here is how can I pass Future<void> functionName to the Utils widget so that it can be used in other API calls?
What I tried:
static Future<void> userLogin(BuildContext context, String email,
String password, bool rememberMe) async {
// does something
} on TimeoutException {
Utils().showTimeoutDialog(context, userLogin);
then in my Utils class:
showTimeoutDialog(BuildContext context, Function callback) {
onPress: () async { await callback;}
it works but the callback is being called immediately without even pressing the button.

Flutter - How to call functions (and variables) between stateful widgets?

I have this function in a widget (homescreen):
void toggleRecording() async {
// HERE IS THE CONFUSION I GUESS
_isRecording = !_isRecording;
recorder = SoundStream(isRecording: _isRecording);
//recorder.toggleRecording(_isRecording);
setState(() {
_isRecording = recorder.isRecording;
});
if (_isRecording) {
startTimer();
_stopwatch.start();
} else {
stopTimer();
_stopwatch.stop();
}
}
It needs to call (trigger) another function in my recorder class:
void toggleRecording() async {
widget.isRecording ////// currently being passed as an argument from homescreen
? {_recorder.stop, await save(_micChunks, 44100)}
: _recorder.start;
}
Also, the boolean variable _isRecording is present in both the classes. How do I sync the state?
In your situation passing reference of function through widgets will work. However best practice of this will be using provider package.
Managing functions from provider will allow you to control functions from all pages.
If you change a variable you can call notifylistener() function inside your provider function. So that you can change state of widget.
I will try to explain it in a glance however this is an important subject of flutter.
Here is my folder structure
At provider folder we define our provider classes.
Firstly i define class which extends changeNotifier class. This is what make this class provider.
Side note: notifyListener() function here calls setState of every widget if you use any variables inside that class and this is what you are searching for.
Then i import it into my main.dart file or whatever file you want. Only condition is being above the widget that you will use provider at.
At last you can use your function at everywhere if you import provider package and define your provider like i did in this code.
At last here is the visualized stucture of provider package.
I wish i explained it well. There is more about it on youtube.
Pass the function to other widget
using Function keyword
Say ContentWidget is your child and ParentWidget is parent
class ParentWidget extends StatefulWidget {
//Do Something
void onSomeFunction()
{
ContentWidget(onTimerUpdate:onTimerClosed)
}
void onTimerClosed()
{
//Perform Operation on Timer Change
}
}
class ContentWidget extends StatefulWidget {
final Function onTimerUpdate;
ContentWidget({
Key key,
#required this.onTimerUpdate,
}) : super(key: key);
void onAnyActionFromChild()
{
widget.onTimerUpdate() //Note () can have any param or can be null
}

Navigation inside future method flutter

I am trying to navigate to a screen from a future method. However I get an error saying undefined name context. I tried navigating from Widget build but the parameter is created within this method and I need it for navigating. I've been stuck on this for a very long time. Any help will be really appreciated.
Future<void> addBookingConversation(Booking booking) async {
Conversation conversation = Conversation();
await conversation.addConversationToFirestore(booking.posting.host); //additional method working fine
String text = "Hi, my name is ${AppConstants.currentUser.firstName}";
await conversation.addMessageToFirestore(text); //additional method working fine
//this is where i should navigate to the conversation page and facing the error here
Navigator.push(
context, //error here context undefined
MaterialPageRoute(builder:
(context) => ConversationPage(conversation: conversation,),
),
);
}
class ConversationPage extends StatefulWidget {
final Conversation conversation;
static final String routeName = '/conversationPageRoute';
ConversationPage({this.conversation, Key key}) : super(key: key);
#override
_ConversationPageState createState() => _ConversationPageState();
}
class _ConversationPageState extends State<ConversationPage> {
Conversation _conversation;
// additional code of wiget build
}
I don't know where your function resides, so this is some general advice:
If you cannot access a variable in your method you have two options: pass it in as a parameter from the caller. Or return the result to the caller so they can do the part where the variable is needed themselves.
What does that mean for your scenario: either you need the context as an additional parameter in your method, or you need to return Future<Conversation> from your method and handle the navigation where it's called.
Personally, I'd favor the second option, since your business logic of starting a conversation and your in-app navigation are two different concerns that should not be mixed in one method.
If you want to call the navigator method anywhere in the app.
class NavigationService {
final GlobalKey<NavigatorState> globalKey = GlobalKey<NavigatorState>();
Future<dynamic> navigateTo(Route Route) {
return globalKey.currentState.push(Route);
}
}
and in main.dart.
navigatorKey: NavigationService().globalKey,
and then anywhere within the app.
Just use this
Future<void> addBookingConversation(Booking booking) async {
Conversation conversation = Conversation();
await conversation.addConversationToFirestore(booking.posting.host);
//additional method working fine
String text = "Hi, my name is ${AppConstants.currentUser.firstName}";
await conversation.addMessageToFirestore(text); //additional method working
fine
//this is where i should navigate to the conversation page and facing the
error here
NavigationService().navigateTo(
MaterialPageRoute(builder:
(context) => ConversationPage(conversation: conversation,),
),);
}
Wrap your Navigator inside :
WidgetsBinding.instance.addPostFrameCallback((_){
// 👈 Your Navigation here
});
Your Code:
Future<void> addBookingConversation(Booking booking) async {
...
WidgetsBinding.instance.addPostFrameCallback((_){
Navigator.push( //👈 add your navigation here
context, //error here context undefined
MaterialPageRoute(builder:
(context) => ConversationPage(conversation: conversation,),
),
);
...
}
This method help you to navigate the route without FutureBuilder. see the code
onPressed: () async {
// then await the future You want to complete and then use `.then()`
//method to implement the code that you want to implement when the future is completed
await //call your future widget //
.then((result) {
print('future completed');
// Navigate here
// For errors use onError to show or check the errors.
}).onError((error, stackTrace) {
print(error);
});
}

Where do I put commands that run once at beginning?

I really miss C programming. Flutter is quite confusing.
Here is the problem:
We have a function within the Stateful class Home. That creates a page called myMenu.
class Home extends StatefulWidget {
myMenu createState() => myMenu();
}
class myMenu extends State<Home>
{
void myProblemFunction(String stringItem) async {
final db = await myDatabaseClass.instance.database;
...
}
Whenever myProblemFunction runs, it will instantiate a new database instance.
I just want to put this command once (i.e.:
final db = await myDatabaseClass.instance.database
) anywhere in my document (this is my main.dart file (by the way). Now, I could put it in the initState() - sure.. but that's a headache, because a) I would have to make it async, and I feel that will cause me problems, and b) declaring final db... (etc) in the initState() will not make the db variable visible to my functions.
What do I do?
what are the elements in myMenu Class that are triggered? Should I put this function inside the widget build method? But surely if the widget is refreshed, then this function will also be called (again) - I just want to call it once.
Thanks
you can use FutureBuilder
example:
FutureBuilder(
future: myDatabaseClass.instance.database,
builder: (BuildContext context,AsycnSnapshot snapshot){
//your code here
},
)
this will only load the Future once when the widget is built.
put your code that you want to run only once in initState():
#override
void initState() {
super.initState();
// TODO code you want to run only once
}