I want to save in a variable the user's uid brought from Firebase to later make a query with MySql but it gives me an error, I Want print in console the variable too, my code is as follows
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Bienvenido')),
body: Container(
child: Column(
children: <Widget>[
BlocBuilder<AuthCubit, AuthState>(
buildWhen: (previous, current) => current is AuthSignedIn,
builder: (_, state) {
final authUser = (state as AuthSignedIn).user;
return Center(
child: Column(
children: [
Text('Usuario: ${authUser.uid}'),
SizedBox(
height: 16,
),
ElevatedButton(
onPressed: () => context.read<AuthCubit>().signOut(),
child: Text('Salir'))
],
),
);
}
),
],
),
),
);
The element type 'String' can't be assigned to the list type 'Widget'. is this line.
Text('Usuario: ${authUser.uid}'), usuario=authUser.uid;
Related
I cannot find a satisfactory way for a grandchild widget to trigger a grandparent state change. My app saves and sources its data all from an on-device database.
Ive tried to proceed this far without using a state management library as I thought this was overkill - the app is not complex.
Ive got a ListView (grandparent), which in turn has children that are my own version of ListTiles. There are two icon buttons on each ListTile, one to edit and one to delete - both of which trigger a different alertdialog (grandchild) popup. When I perform an update or delete on the data, it is written to the db and a Future is returned - and then I need the grandparent ListView state to refresh. StatefulBuilders will only give me a way to refresh state on the grandchild (separately from the child), not a way to trigger 'multi level' state change.
Is it time for a state management solution such as BLOC or Riverpod, or is there any other solution?
ListView Grandparent Widget
#override
Widget build(BuildContext context) {
return Scaffold(
body: Builder(
builder: (BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
// other children here
Expanded(
flex: 11,
child: FutureBuilder<List<MyCustomObject>>(
future: _getQuotes(), // queries the db
builder: (context, AsyncSnapshot snapshot) {
if (snapshot.connectionState == ConnectionState.waiting
&& !snapshot.hasData) {
return const Center(
child: SizedBox(
height: AppDims.smallSizedBoxLoadingProgress,
width: AppDims.smallSizedBoxLoadingProgress,
child: CircularProgressIndicator()
),
);
} else if (snapshot.hasError) {
log(snapshot.error.toString());
log(snapshot.stackTrace.toString());
return Center(child: Text(snapshot.error.toString()));
} else {
// no point using StatefulBuilder here, as i need
// to potentially trigger _getQuotes() again to rebuild the entire ListView
return ListView.builder(
padding: const EdgeInsets.symmetric(
horizontal: AppDims.textHorizontalPadding,
vertical: AppDims.textVerticalPadding
),
itemCount: snapshot.data!.length,
itemBuilder: (context, int index) {
return MyCustomTile(
// tile data mapping from snapshot for MyCustomObject
);
},
);
}
},
)
)
]
);
}
)
);
}
MyCustomTile Child Widget
#override
Widget build(BuildContext context) {
return Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppDims.tileBorderRadius),
side: const BorderSide(
color: Colors.green,
width: 1.5,
)
),
child: ListTile(
// other omitted ListTile params here
trailing: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
icon: const Icon(Icons.edit),
onPressed: () => showDialog(
context: context,
barrierDismissible: true,
builder: (BuildContext context) {
return EditDialog();
}
).then((_) => setState(() {})), // will only setState on the dialog!
),
IconButton(
icon: const Icon(Icons.delete),
onPressed: () => showDialog(
context: context,
barrierDismissible: true,
builder: (BuildContext context) => DeleteWarningDialog(
widget.id,
AppStrings.price.toLowerCase(),
true
),
),
),
]
),
),
);
}
DeleteWarningDialog Grandchild Widget
#override
Widget build(BuildContext context) {
return AlertDialog(
title: Text(_buildFinalWarningString()),
actions: [
TextButton(
child: const Text(AppStrings.cancel),
onPressed: () => Navigator.pop(context),
),
TextButton(
child: const Text(AppStrings.delete),
onPressed: () {
_appDatabase.deleteFoo(widget.objectIdToDelete);
Navigator.pop(context);
},
)
],
);
}
you will have to declare a function in the grandParent which is the listView in your case and pass it to parent and children's. but it will be so complicated and not really efficient, using state management would make it a lot easer and clean
So I have a main screen that I want to display straight away to an old user of the app (Meaning token has been set) but to a new user, I want to display a column with some information etc. first and after the user presses the button it will open the main screen. However, the below code doesn't work as I wish (this doesn't change the view in any way). What would be the correct approach to this problem?
#override
Widget build(BuildContext context) {
return FutureBuilder<bool>(
future: getPrefs(),
builder: (context, AsyncSnapshot<bool> snapshot) {
if (snapshot.hasData) {
if(token == null){
return Column(
verticalDirection: VerticalDirection.up,
children: [
ElevatedButton(
onPressed: (){
return mainScreen();
},
),
],
);
}
else{
return mainScreen();
}
} else {
return CircularProgressIndicator();
}
}
);
Widget mainScreen(){
return Scaffold(
appBar: AppBar(
title: Text('Feed planner',
style: TextStyle(fontSize: 17),
),
toolbarHeight: 50,
actions: [
IconButton(icon: icon, onPressed: _pushSettings),
],
),
body: Center(
child: Column(
children: [
Expanded(child: _buildGrid()),
]
)
)
);
}
Edit 1, after OP provided more info:
Make your homescreen widget like this:
Widget mainScreen(bool token){
return Scaffold(
appBar: AppBar(
title: Text('Feed planner',
style: TextStyle(fontSize: 17),
),
toolbarHeight: 50,
actions: [
IconButton(icon: icon, onPressed: _pushSettings),
],
),
body: Center(
child: Column(
children: [
token == null ? Text('Add your text or widget here for new users') : Container()
Expanded(child: _buildGrid()),
]
)
)
);
}
And your Future builder like this:
FutureBuilder<bool>(
future: getPrefs(),
builder: (context, AsyncSnapshot<bool> snapshot) {
if (snapshot.hasData) {
return mainScreen(snapshot); //or the token you are getting
}
else {
return CircularProgressIndicator();
}
})
The problem is here:
ElevatedButton(
onPressed: (){
return mainScreen();
},
)
You should use:
ElevatedButton(
onPressed: (){
Navigator.pushNamed(context, '/mainScreen'); //or whatever the name of your home screen is in routes.
},
)
I have looked for similar answers and tried using their proposed solutions with no success. I am trying to build a ListView with data from the Firestore. Everytime I try to run it, it gives me a "Type 'List' is not a subtype of type 'Widget'".
Thank you in advance!
Here are the two blocks of code involved in the error:
class Test extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection("exercises").snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData) return new Text("There is no expense");
return new Scaffold(
backgroundColor: Colors.blue[100],
appBar: AppBar(
title: Text('Test'),
backgroundColor: Colors.blue[400],
elevation: 0.0,
),
body: Column(
children: <Widget>[
ListView(
shrinkWrap: true,
padding: EdgeInsets.all(0),
children: <Widget>[getExpenseItems(snapshot)]
)
],
),
);
});
}
getExpenseItems(AsyncSnapshot<QuerySnapshot> snapshot) {
return snapshot.data.documents.map<Widget>((doc) =>
new Container(
child: Card(
child: ListTile(
title: new Text(doc["nome"]),
subtitle: new Text(doc["link"])
),
),
)
).toList();
}
Spread the returned list of widgets from getExpenseItems(snapshot):
body: Column(
children: <Widget>[
ListView(
shrinkWrap: true,
padding: EdgeInsets.all(0),
children: <Widget>[...getExpenseItems(snapshot)]
)
],
),
//....
I have BlocProvider widget above the widget where I'm trying to dispatch event, but I still getting BlocProvider.of() called with a context that does not contain a Bloc of type RenderBloc.
This is what my build method returns:
return BlocProvider<RenderBloc>(
builder: (BuildContext context) => RenderBloc(),
child: Column(
children: <Widget>[
FlatButton(
child: Text('Render'),
onPressed: () {
BlocProvider.of<RenderBloc>(context).add(RenderProjectEvent(project));
},
)
],
),
);
I also tried with MultiBlocProvider, got the same.
You need to create another inner context (using Builder, for example) to access InheritedWidget (Provider):
return BlocProvider<RenderBloc>(
builder: (BuildContext context) => RenderBloc(),
child: Builder(
builder: (cxt) {
return Column(
children: <Widget>[
FlatButton(
child: Text('Render'),
onPressed: () {
BlocProvider.of<RenderBloc>(cxt).add(RenderProjectEvent(project));
},
)
],
),
),
}
);
Im doing a flutter app for currency exchange, on the call of the function to print the value, only get the last value for all
basically this only get the last value of getvalue and put for all of the values.
class BodyWidgetState extends State<BodyWidget> {
#override
Widget build(BuildContext context) {
return Scaffold (
appBar: AppBar(title: Text(moed)),
body: ListView(
children: <Widget> [
ListTile (
leading: CircleAvatar(
backgroundImage: AssetImage('assets/mxn.png'),
),
title: Text('MXN'),
),
getValue(moed,'MXN'),
ListTile(
leading: CircleAvatar(
backgroundImage: AssetImage('assets/eur.png'),
),
title: Text('EUR'),
),
getValue(moed,'EUR'),
Widget getValue (String b, String c){
return (
FutureBuilder<Quote> (
future : getQuote(b,c),
builder: (context, snapshot) {
if (snapshot.hasData) {
return Center(
child: Column(
children: <Widget>[
SizedBox(height: 10),
Text(snapshot.data.coin.toString()),
],
));
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
return CircularProgressIndicator();
}));}