Cannot share a file as it need to wait a future - flutter

Share() must display a modal in order to let the user wait in front of a circular progress indicator while I am loading the video file URL.
My code is as below, but I am puzzled about how to architecture: I need to trigger the sharing only once the snapshot.hasData.
How can that be done?
Btw, I use share_plus
Future<void> share(BuildContext context) async {
showModalBottomSheet(
context: context,
builder: (context) {
return FutureBuilder(
future: Video.videoUrl(videoUrl!),
builder: (context, snapshot) {
final file = XFile(snapshot.data!);
Share.shareXFiles([file],
text: "Don't miss this out! Only on Shokaze");
return SizedBox(
height: 200,
child: Center(
child: !snapshot.hasData
? Column(children: [
Text("Preparing sharing…"),
const CircularProgressIndicator(),
])
: Text("Sharing…")));
});
});
}

You should refactor the FutureBuilder using if/else conditions:
if (snapshot.hasData) {
Share.share(snapshot.data!);
return Text(snapshot.data.toString());
} else if (snapshot.hasError) {
return Text(snapshot.error.toString());
} else {
return Scaffold(body: Center(child: CircularProgressIndicator()));
}
Future<void> share(BuildContext context) async {
showModalBottomSheet(
context: context,
builder: (context) {
return FutureBuilder(
future: myFuture(),
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
if (snapshot.hasData) {
Share.share(snapshot.data!);
return Text(snapshot.data.toString());
} else if (snapshot.hasError) {
return Text(snapshot.error.toString());
} else {
return Scaffold(body: Center(child: CircularProgressIndicator()));
}
},
);
},
);
}

Related

returning a FutureBuilder as the result of a FutureBuilder Flutter

I'm creating an add friend page in Flutter/Firebase. I used a StreamBuilder to see the changes of the username input. Then I used a FutureBuilder as the result of the StreamBuilder to get my List of User. To verify that the users aren't already in thisUser's friend list, I'm using an other FutureBuilder as the result of the first one. And I still do the same for the friend requests.
It works but I'm pretty sure that not the right way. Could someone explain me how to do that more properly?
StreamBuilder(
stream: controller.usernameStream.stream,
builder: (context, snapshot) {
if (snapshot.hasData) {
String usernameSearched = snapshot.data!;
return FutureBuilder(
future: _userRepo.getUsersStartsByUsername(usernameSearched),
builder: (context, snapshotUsers){
if(snapshotUsers.connectionState == ConnectionState.done){
if (snapshotUsers.hasData){
return controller.futureBuilderFriends(thisFireUser, snapshotUsers);
} else {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Center(child: Text(AppLocalizations.of(context)!.noUsers)),
);
}
}
return Container();
},
);
}
return Container();
},
)
FutureBuilder<List<String>> futureBuilderFriends(User? thisFireUser, AsyncSnapshot<List<U.User>> snapshotUsers) {
return FutureBuilder(
future: _userRepo.getFriendsId(thisFireUser!.uid),
builder: (BuildContext context, AsyncSnapshot<List<String>> snapshotFriends) {
if (snapshotFriends.connectionState == ConnectionState.done) {
if(snapshotFriends.hasData){
return futureBuilderMyFriendRequests(thisFireUser, snapshotFriends.data!, snapshotUsers);
} else {
return futureBuilderMyFriendRequests(thisFireUser, [], snapshotUsers);
}
} else {
return Container();
}
},
);
}
FutureBuilder<List<String>> futureBuilderMyFriendRequests(User thisFireUser, List<String> friends, AsyncSnapshot<List<U.User>> snapshotUsers) {
return FutureBuilder(
future: _userRepo.getFriendRequestsId(thisFireUser.uid),
builder: (BuildContext context, AsyncSnapshot<List<String>> snapshotFriendRequests) {
if (snapshotFriendRequests.connectionState == ConnectionState.done) {
if(snapshotFriendRequests.hasData){
return buildAddFriends(context, snapshotUsers.data!, thisFireUser, friends, snapshotFriendRequests.data!);
} else {
return buildAddFriends(context, snapshotUsers.data!, thisFireUser, friends, []);
}
} else {
return Container();
}
},
);
}
Looks like you are on vanilla architecture. Please make use of bloc or Riverpod and use the transfrom functions and emit the states accordingly

Hi, I have problem with the property (title) and the bracket of (bluilder)... I'm just fetch data from API

class _Requests_TabState extends State<Requests_Tab> {
Future<Product> productdata = getPostById();
#override
Widget build(BuildContext context) {
return Scaffold(
extendBody: true,
body: Center(
child: FutureBuilder(
future: productdata,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text(snapshot.data.title);
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
CircularProgressIndicator();
},
),
),
return Text(snapshot.data[title].toString());

Instance of 'Future<dynamic>' . I am getting this error and unable to load information

final String apiUrl = 'https://api.covid19api.com/summary';
Future globaldata() async{
var res = await http.get(Uri.parse(apiUrl));
Map s = await jsonDecode(res.body);
return s['Global']['NewConfirmed'];
}
//....
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("global cases"),
centerTitle: true,
),
body:Container(
child: FutureBuilder(
future: globaldata(),
builder: (context, snapshot){
if(snapshot.data != null){
print(globaldata());
return Text(globaldata().toString());
}else{
return Text("loading ...");
}
},
),
),
);
}
}
I am getting error of Instance of 'future'
Try doing these
child: FutureBuilder(
future: globaldata(),
builder: (context, snapshot) {
if(snapshot.data != null){
print(snapshot.data);
return Text(snapshot.data);
}else{
return Text("loading ...");
}
},
),
),
);
Check Print and return Text statement
You get this error because you are printing and returning Futures without await:
print(globaldata());
return Text(globaldata().toString());
Your FutureBuilder provides you the values you are trying to access in snapshot:
print(snapshot.data);
return Text(snapshot.data.toString());
Change your function to this.
Future globaldata() async {
http.Response response = await http.get(Uri.parse(apiUrl));
if (response.statusCode == 200) {
return jsonDecode(response.body)['Global']['NewConfirmed'];
} else {
throw Exception('Failed to load post');
}
}
and change your body to this.
body: FutureBuilder(
future: globaldata(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return Center(
child: Text(snapshot.data.toString()),
);
} else if (snapshot.hasError) {
return Center(
child: Text("${snapshot.error}"),
);
}
return const Center(
child: CircularProgressIndicator(),
);
},
),
This works perfectly.

Close loading dialog in FutureBuilder

I am using Futurebuilder in flutter and having issue while closing the showDialog
Widget build(BuildContext context) {
return Scaffold(
appBar: PreferredSize(
preferredSize: Size( 50.0),
body: FutureBuilder(
future: widget.getAutoCompleteData(),
builder: (context, snapshot) {
if (snapshot.hasData) {
Navigator.of(context).pop();
} else if (snapshot.hasError) {
} else {
LoadingDialog.showLoadingDialog(context, _scaffoldKey);
}
return Center(
child: Container(child: Text("sds"),),
);
}));
}
Getting below error when screen loads
package:flutter/src/widgets/navigator.dart': Failed assertion: line 5013 pos 12: '!_debugLocked': is not true
Change this
FutureBuilder(
future: widget.getAutoCompleteData(),
builder: (context, snapshot) {
if (snapshot.hasData) {
Navigator.of(context).pop();
} else if (snapshot.hasError) { //here this is empty
} else {//remove else statement
LoadingDialog.showLoadingDialog(context, _scaffoldKey);
}
return Center(
child: Container(child: Text("sds"),),
);
})
To This
FutureBuilder<List<Post>>(
future: _dataFetcher.getPosts(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(),
);
}
if (snapshot.hasError) {
return LoadingDialog.showLoadingDialog(context, _scaffoldKey);
}
return Center(child: Text('${snapshot.data![0].title}'));
},
)
It may be caused by the re-entrant of the Navigator (you can check the answer here: Error thrown on navigator pop until : “!_debugLocked': is not true.”
)
Or, maybe you don't want to use FutureBuilder. The FutureBuilder is meant to stay in the same widget/page and show different screens when future data is not ready. If you want to push a loading dialog and close it when data is ready, you can just simply use a Future function
Future pressTheButton(context) async {
LoadingDialog.showLoadingDialog(context, _scaffoldKey); // showDialog here
final data = await getAutoCompleteData(); // await the data
Navigator.of(context).pop(); // pop the loading dialog
// return your data or error
// or rebuild the current widget with the data
}

FutureBuilder snapshot Data does not return anything , Why?

Trying to get stored data by SharedPreferences But does not work ..
my main.dart :
Widget build(BuildContext context) {
return StreamProvider<User>.value(
value: AuthService().user,
child: FutureBuilder<String>(
future: SaadConstants.setValueFromLocal('app_lang','ar'),
builder: (BuildContext context, AsyncSnapshot<String> snapshot){
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body:Wrapper(),
),
);
}
),
);
}
my wrapper :
#override
Widget build(BuildContext context) {
final user = Provider.of<User>(context);
if (user==null) {
return FutureBuilder(
future: SaadConstants.getValueFromLocal('app_lang'),
builder: (BuildContext contect , AsyncSnapshot<String> snapshot){
if (snapshot.hasData) {
return Text('has data');
}
else return Text('None');
}
);
}
else{
return Text('connect');
}
it returns this widget : Text('None') ..
my setValue Function :
static Future<String> setValueFromLocal(String key, String value) async { // Async func to handle Futures easier; or use Future.then
SharedPreferences perfs = await SharedPreferences.getInstance();
perfs.setString(key.toString(),value.toString());
}
my getValue Function :
static Future<String> getValueFromLocal(String key) async { // Async func to handle Futures easier; or use Future.then
SharedPreferences perfs = await SharedPreferences.getInstance();
return perfs.getString(key);
}
Try this,
return FutureBuilder(
future: SaadConstants.getValueFromLocal('app_lang'),
builder: (BuildContext contect, AsyncSnapshot<String> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting)
return Center(child: CircularProgressIndicator());
else if (snapshot.hasData)
return Text("DATA: ${snapshot.data}");
else if (snapshot.hasError)
return Text("ERROR: ${snapshot.error}");
else
return Text('None');
}
);
Your main.dart should also implement these conditions.
Widget build(BuildContext context) {
return StreamProvider<User>.value(
value: AuthService().user,
child: MaterialApp(
debugShowCheckedModeBanner: false,
home: FutureBuilder<String>(
future: SaadConstants.setValueFromLocal('app_lang', 'ar'),
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting)
return Center(child: CircularProgressIndicator());
else if (snapshot.hasError)
return Text("ERROR: ${snapshot.error}");
else
return Scaffold(
body: Wrapper(),
);
}
),
),
);
}