Flutter: get bool value from snapshot - flutter

I am trying to show an on-boarding screen so to do so I call an async function where I get a Future<bool> weather this is the first time the user launched the app. Since its a Future value I have decided to use FutureBuilder.
Here is part of the code of what I am trying to do:
#override
Widget build(BuildContext context) {
return GetMaterialApp(
home: FutureBuilder(
future: firstLaunch, //Future<bool> value
builder: (context, snapshot) {
if (snapshot.hasData) {
// What I would like to do is use either one of these lines
// return _firstLaunch ? const OnboardingScreen() : const WelcomePage();
// return snapshot.data ? const OnboardingScreen() : const WelcomePage();
} else {
return const WelcomePage();
}
},
),
);
}
The issue is that I am unable to use _firstLaunch within the FutureBuilder since its still considered a future value and snapshot.data does give me the correct value when I print it but the type is AsyncSnapshot<Object?> so I also cant seem to use it.
Does anyone have suggestions on how to solve this or possibly know of a better way to show the on-boarding screen?

Prefer documentation:
https://api.flutter.dev/flutter/widgets/FutureBuilder-class.html
Try this:
#override
Widget build(BuildContext context) {
return GetMaterialApp(
home: FutureBuilder<bool>(
future: firstLaunch, //Future<bool> value
builder: (BuildContext context, AsyncSnapshot<bool> snapshot) {
if (snapshot.hasData) {
return snapshot.data ? const OnboardingScreen() : const WelcomePage();
} else {
return const WelcomePage();
}
},
),
);
}

Use a bool inside has data
if (snapshot.hasData) {
bool check = snapshot.data;
return check ? const OnboardingScreen() : const WelcomePage();
}

Related

How to make Flutter Stream Builder return seamlessly

I have a little problem here where i have logged in with Google Auth using Firebase but everytime i tried to restart the app i expect the app will show the HomePage() without any problem, but i found that before it return, the app had like a bit seconds in LoginPage() before displaying HomePage(), is there any way to make it seamlessly
class AuthService extends StatelessWidget {
const AuthService({super.key});
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
body: StreamBuilder(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return HomePage();
} else {
return LoginPage();
}
},
),
);
}
}
It is happening because for snapshot to reach snapshot.hasData state it takes time, and meanwhile else part is executed which is LoginPage().
How to overcome this?
Try to wrap within snapshot.connectionState == ConnectionState.active which means once stream is connected then check the condition else return CircularProgressIndicator
Code:
StreamBuilder(
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.active) {
if (snapshot.hasData) {
return HomePage();
} else {
return LoginPage();
}
}
return const CircularProgressIndicator();
},
);

How do I incorporate a function where return is a String into a string?

I created a function with a return value of String as follows.
Future<String?> setName() {
String? name='Jon';
return name;
}
Is there any way to incorporate this into the string?
I want to use following situations.
print('Name:${setName}');
or
appBar: AppBar(
title: Text('Name:${setName}'),
When I wrote the above, it unexpectedly output the following
Name:Closure:()=> Future<String?> from Function ...
You could either set a variable to the current state (loading, loaded) and switch the UI accordingly like
return isLoading ? LoadingView() : LoadedView()
or you just pass the future in a FutureBuilder and handle the logic inside it
return FutureBuilder<String>(
future: setName(), // a previously-obtained Future<String> or null
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
if (snapshot.hasData) {
return LoadedView();
} else {
return LoadingView();
},
}
),
);
It would be better if you use FutureBuilder for future method.
Create a state future variable.
class _TestXState extends State<TestX> {
Future<String?> setName() async {
String? name = 'Jon';
await Future.delayed(Duration(seconds: 2));
return name;
}
late final nameFuture = setName();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: FutureBuilder(
future: nameFuture,
builder: (context, snapshot) {
if (snapshot.hasData) return Text("${snapshot.data}");
return Text("....");
},
),
),
);
}
}

In Flutter, is there a way get item in flutter secure storage in widget?

I want to take a data from flutter secure storage. But as you know its a async function for get it. So in my widget , how can i take that data ? I cant use await for take it. So how can i take it ? Thanks for response!
Code :
FutureBuilder<PurchasedPackageResponseModel?>(
future: service.getPurchasedPackages(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return const Center(
child: CircularProgressIndicator(),
);
}
I want to take data here ==> bool isClientTherapist = (I cant use await here So its giving error.) UserSecureStorage.getField("isClientTherapist");
final model = snapshot.data!.data!;
if (model.isEmpty) {
return const NotBoughtSessionWidget();
}
return const SizedBox();
If i make it stateful widget i can take in initstate. But i using getx and i want to take in stateless widget. Is it possible ?
You can simply add another FutureBuilder inside the first one to await this second call.
FutureBuilder<PurchasedPackageResponseModel?>(
future: service.getPurchasedPackages(),
builder: (context, snapshot1) {
if (!snapshot1.hasData) {
return const Center(
child: CircularProgressIndicator(),
);
}
return FutureBuilder<bool?>(
future: UserSecureStorage.getField("isClientTherapist"),
builder: (context, snapshot2) {
if (!snapshot2.hasData) {
return const Center(
child: CircularProgressIndicator(),
);
}
final isClientTherapist = snapshot2.data!;
final model = snapshot1.data!.data!;
if (model.isEmpty) {
return const NotBoughtSessionWidget();
}
return const SizedBox();
},
);
},
)

The body might complete normally, causing 'null' to be returned, but the return type is a potentially non-nullable type. / Flutter

I just started writing with Flutter.I am constantly getting this error. What should i do? Here is my code:
#override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder<WeatherInfo>(
future: futureWeather,
builder: (context, snapshot) {
if (snapshot.hasData) {
} else if (snapshot.hasError) {
return Center(
child: Text("${snapshot.error}"),
);
#override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder<WeatherInfo>(
future: futureWeather,
builder: (context, snapshot) {
if (snapshot.hasData) {
} else if (snapshot.hasError) {
return Center(
child: Text("${snapshot.error}"),
);
}
return const Center(child: CircularProgressIndicator());
}));
}
Inside the FutureBuilder you covered the case in which you have the data or you have an error, but not when you are expecting for the future to complete(And don't have neither the data or an error).
I just added a Circular progress indicator to be shown while no data or no error are returned from the Future, that should prevent the FutureBuilder from returning null. And when the snapshot state changes the data or error would be shown.
I think you should try and wrap the future builder in a container

How can I update the value of the parameter with the value that come from API response?

I am trying to update the value of totalPricewith the value that comes from the response from API. I have created a currentTotal methods that contains setState(). Then passed snapshot.data.price.totalAmountvalue to currentTotal in order to update the value of totalPrice.But, it doesnt update the value. Can you help?
double totalPrice = 0;
#override
Widget build(BuildContext context) {
currentTotal(double x) {
setState(() {
totalPrice += x;
});
}
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: FutureBuilder<SearchResult>(
future: serviceOne.postCall(),
builder: (context, snapshot) {
if (snapshot.hasData) {
if (snapshot.data != null) {
return new Material(
child: CustomScrollView(
slivers: <Widget>[
SliverList(
delegate: SliverChildListDelegate([
ListTile(
title: new Text(totalPrice.toString()),
)
]),
),
]
)
}
currentTotal(snapshot.data.price.totalAmount);
else if (snapshot.hasError) {
return Text("error....${snapshot.error}");
}
There are many things needs to be fixed in your build.
1 - Your widget is StatefulWidget, to use FutureBuilder inside StatefulWidget read this:
https://api.flutter.dev/flutter/widgets/FutureBuilder-class.html
Briefly, create Future future; instance field, then assign it inside the initState and use that future for FutureBuilder.
2 - your setState not inside a method, you have probably syntax error there. Create a void method and use setState inside it.
3 - You don't need to check twice like:
if (snapshot.hasData) {
if (snapshot.data != null) {
One of them enough, after the condition check, call your method includes setState, then display it.
Edit:
Here an example template for your solution:
class Test extends StatefulWidget {
#override
_TestState createState() => _TestState();
}
class _TestState extends State<Test> {
Future<int> future;
int price = 0;
#override
void initState() {
future = fetchPrice();
super.initState();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: FutureBuilder<int>(
future: future,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Center(
child: Text(price.toString()),
);
}
return Center(child: CircularProgressIndicator());
},
),
),
);
}
Future<int> fetchPrice() async {
final response =
await http.get('https://jsonplaceholder.typicode.com/posts/1');
final data = json.decode(response.body);
setState(() {
price = data['userId'];
});
return data['userId'];
}
}