i am trying to displaying the new value every time the user click the button but it keeps displaying the old data. I need to hot restart to see the new data after i update it. I do not know what i did wrong because i am still learning. This is my full code. I hope someone can help me because i am stuck here 3 hours +
TextEditingController _reloadEditingController = new TextEditingController();
int balance = 0;
late int s = int.parse(_reloadEditingController.text);
final _formKey = GlobalKey<FormState>();
String? name;
String email = '';
String phoneNumber = '';
String imageUrl = '';
String joinedAt = '';
String location = '';
void reload() async {
FirebaseFirestore.instance
.collection("users")
.doc(widget.userID)
.update({"balance": balance + s});
}
void getUserData() async {
try {
_isLoading = true;
final DocumentSnapshot userDoc = await FirebaseFirestore.instance
.collection('users')
.doc(widget.userID)
.get();
if (userDoc == null) {
return;
} else {
setState(() {
name = userDoc.get('name');
email = userDoc.get('email');
phoneNumber = userDoc.get('phoneNumber');
imageUrl = userDoc.get('userImage');
location = userDoc.get('location');
balance = userDoc.get('balance');
});
final FirebaseAuth _auth = FirebaseAuth.instance;
User? user = _auth.currentUser;
final _uid = user!.uid;
setState(() {
_isSameUser = _uid == widget.userID;
});
}
} catch (error) {
} finally {
_isLoading = false;
}
}
void initState() {
super.initState();
getUserData();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.teal[300],
appBar: AppBar(
title: const Text('Wallet'),
flexibleSpace: Container(
color: Colors.teal[300],
),
leading: IconButton(
onPressed: () {
final FirebaseAuth _auth = FirebaseAuth.instance;
final User? user = _auth.currentUser;
final String uid = user!.uid;
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (_) => ProfileScreen(
userID: uid,
)));
},
icon: Icon(Icons.arrow_back, size: 40, color: Colors.white)),
),
body: ListView(
children: [
Column(
children: [
Container(
width: 300,
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16),
color: Color(0xFF006e6e)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Text(
name!,
style: TextStyle(color: Colors.white, fontSize: 18),
),
],
),
],
),
),
Container(
padding: EdgeInsets.all(10),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 25),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Row(
children: [
Text(
"Balance",
),
],
),
Row(
children: [
Text(
'RM',
),
Container(
child: FutureBuilder<DocumentSnapshot>(
future: FirebaseFirestore.instance
.collection('users')
.doc(widget.userID)
.get(),
builder: (context, snapshot) {
if (snapshot.connectionState ==
ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(),
);
}
return Text(balance.toString());
},
),
),
],
),
Row(
children: [
Text("Reload your E-Wallet",
)
],
),
Row(
children: [
Form(
key: _formKey,
child: Expanded(
child: TextFormField(
controller: _reloadEditingController,
keyboardType: TextInputType.phone,
),
),
)
],
)
],
),
),
),
Container(
width: 320,
child: MaterialButton(
onPressed: () {
reload();
},
child: Padding(
padding: EdgeInsets.symmetric(vertical: 14),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Reload E-Wallet",
)
],
),
),
),
),
],
)
],
));
You need yo call getUserData when you update your data so change your reload to this:
void reload() async {
int s = int.parse(_reloadEditingController.text); // define this hear
await FirebaseFirestore.instance
.collection("users")
.doc(widget.userID)
.update({"balance": balance + s});
setState(() {});
}
Solution of this problem depends on Stream, because you want the live data.
You want to upload data and download it for show in the UI.
If you try to use StreamBuilder instead of FutureBuilder, I think it may be help..
For me I use GetX package, and since a while I faced the same problem, I will put the URL for my question and see if you can take an idea..
Flutter: live stream with getx has a problem, it shows data without updating
Related
Up!
I am a beginner in Flutter and I am making an application in which I have a first "boats" route. I access to the list of my boats contained in "Card" thanks to this route. Then, I have a second route, accessible from a button in each of these "Cards" allowing me to access the details of each boat.
To retrieve my data, I use a fake API to perform my tests (mockapi.io). For the list of boats, the route is "/boats". Then for the details of each boat, it becomes "/boats/:id/details". Here is my problem, how do I handle the fact that the id changes depending on the boat selected?
Here is the method to access the API:
Future<List<ListDetails>?> getListDetails({required id}) async
{
var client = http.Client();
var uri = Uri.parse('https://63e21b26109336b6cbff9ce9.mockapi.io/api/v1/boats_control/$id/details');
var response = await client.get(uri);
if(response.statusCode == 200)
{
var json = response.body;
return listDetailsFromJson(json);
}
}
And here is my boat_details view, where I try to display the API data:
class ControlListDetailViewState extends State<ControlListDetailView> {
#override
Widget build(BuildContext context) {
late final id = ModalRoute.of(context)?.settings.arguments;
List<ListDetails>? listDetails;
var isLoaded = false;
print(listDetails);
getData() async {
listDetails = await RemoteService().getListDetails(id: id);
if (listDetails != null) {
setState(() {
isLoaded = true;
});
}
}
#override
void initState() {
super.initState();
getData();
}
And here is my model :
import 'dart:convert';
List<BoatsControl> boatsControlFromJson(String str) => List<BoatsControl>.from(json.decode(str).map((x) => BoatsControl.fromJson(x)));
String boatsControlToJson(List<BoatsControl> data) => json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class BoatsControl {
BoatsControl({
required this.model,
required this.location,
required this.id,
});
String model;
String location;
String id;
factory BoatsControl.fromJson(Map<String, dynamic> json) => BoatsControl(
model: json["model"],
location: json["location"],
id: json["id"],
);
Map<String, dynamic> toJson() => {
"model": model,
"location": location,
"id": id,
};
}
Finally, here is my widget where I use this model:
Widget build(BuildContext context) {
print('ControlViewState - build');
return Scaffold(
drawer: NavDrawableWidget(), // Hamburger menu
bottomNavigationBar: FooterWidget(), // Footer Copyright
appBar: AppBar(
title: Text("${AppSettings.APP_NAME} | ${AppSettings.APP_VERSION}",
style: TextStyle(fontSize: 16)),
),
body: Column(
children: [
Text('\n${AppSettings.strings.controlTitle}',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18)
),
Visibility(
visible: isLoaded,
replacement: const Center(
child: CircularProgressIndicator(),
),
child: const Text(''),
),
if(isLoaded)
Expanded(
child: ListView.builder(
itemCount: boatsControl?.length ?? 0,
itemBuilder: (context, index) {
return Container(
padding: EdgeInsets.all(8.0),
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
side: BorderSide(color: Colors.black12, width: 2),
),
child: Padding(
padding: EdgeInsets.all(8.0),
child: Column(
children: <Widget>[
ListTile(
title: Text('${boatsControl![index].id} | ${boatsControl![index].model}'),
leading: Icon(Icons.anchor),
),
Row(
children: <Widget>[
Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Text(boatsControl![index].location,
style: TextStyle(fontSize: 14)),
],
),
),
Align(
alignment: Alignment.centerRight,
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
CustomFloatingActionControlButton(
onPressed: () =>
{
Navigator.pushNamed(
context, '/controlListDefect',
arguments: boatsControl![index].id
)
},
tag: 'listDefectButton',
icon: Icons.equalizer,
),
],
),
),
],
),
],
),
),
),
);
},
),
)
]
),
);
}
Thank you in advance if you take the time to answer me and help me.
I'm trying to display an image from Firestore in to my UI. But it returns the error above, and the file format also changes when I run it on Edge (not on physical device or Emulator). I can't figure out how. Here's my code.
class ViewPola extends StatefulWidget {
const ViewPola({Key? key}) : super(key: key);
static String id = 'view_pola';
#override
State<ViewPola> createState() => _ViewPolaState();
}
class _ViewPolaState extends State<ViewPola> {
Function getSnaps = () async {
final polaMap = {
'Kode Pola': '',
'Bagian Pola': '',
'image_url': '',
};
FirebaseFirestore.instance
.collection('PolaWillyJKT')
.limit(1)
.get()
.then((snapshot) {
if (snapshot.size == 0) {
FirebaseFirestore.instance.collection('PolaWillyJKT').add(polaMap);
FirebaseFirestore.instance.collection('PolaWillyJKT');
print('add');
} else {
print('disini nge get');
var a = FirebaseFirestore.instance.collection('PolaWillyJKT').get();
Map<String, dynamic> data = a as Map<String, dynamic>;
print(data);
}
});
};
var _selectedItem;
var _showList = false;
#override
void initState() {
getSnaps();
super.initState();
}
final Stream<QuerySnapshot> _polaWilly =
FirebaseFirestore.instance.collection('PolaWillyJKT').snapshots();
#override
Widget build(BuildContext context) {
final screenHeight = ScreenInfo.screenHeight(context);
final screenWidth = ScreenInfo.screenWidth(context);
return StreamBuilder<QuerySnapshot>(
stream: _polaWilly,
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return Text('Something went wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Text("Loading");
}
return SafeArea(
child: Scaffold(
body: Padding(
padding: EdgeInsets.all(25),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const Text(
'Pilih Bagian Pola',
style: TextStyle(fontSize: 25),
),
const SizedBox(
height: 20,
),
DropdownButton(
isExpanded: true,
value: _selectedItem,
items: snapshot.data?.docs
.map(
(value) => DropdownMenuItem(
value: value.get("Bagian Pola"),
child: Text('${value.get("Bagian Pola")}'),
),
)
.toList(),
onChanged: (newValue) {
setState(() {
_selectedItem = newValue.toString();
_showList = true;
});
}),
Padding(
padding: const EdgeInsets.all(25),
child: Visibility(
visible: _showList,
child: Container(
height: screenHeight * 0.4,
child: ListView(
children: snapshot.data!.docs
.where(
(e) => e.get("Bagian Pola") == _selectedItem)
.map((DocumentSnapshot document) {
Map<String, dynamic> data =
document.data()! as Map<String, dynamic>;
return Center(
child: Column(
children: [
Text(
'Bagian Pola: ${data["Bagian Pola"]}',
style: TextStyle(fontSize: 15),
),
const SizedBox(
height: 15,
),
Text(
'Kode Pola : ${data["Kode Pola"]}',
style: TextStyle(fontSize: 15),
),
const SizedBox(
height: 15,
),
Image(
image:
NetworkImage(document.get("Foto Pola")),
height: 200,
width: 200,
), // this is the Image widget where I tried to put the image from firestore
Text(document.get('Foto Pola').toString()),
],
),
);
}).toList(),
),
),
),
),
],
),
),
),
);
},
);
}
}
and here's the class that uploads the image to Firestore
class Input_Pola extends StatefulWidget {
const Input_Pola({Key? key}) : super(key: key);
static String id = 'input_pola';
#override
State<Input_Pola> createState() => _Input_PolaState();
}
class _Input_PolaState extends State<Input_Pola> {
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
void _checkDuplicate() {
if (options.contains(_textfieldValue.text)) {
// Display bottom sheet that says item already exists
_scaffoldKey.currentState?.showBottomSheet((context) => Container(
height: 300,
child: Column(
children: [
const Text('Item already exists'),
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('Dismiss'))
],
),
));
} else {
// Add item to options list
setState(() {
options.add(_textfieldValue.text);
});
}
}
XFile? image;
final ImagePicker picker = ImagePicker();
String _image_url = '';
void _addToFirebase(String dropdownValue, String _kodePolaController) {
var imageFile = File(image!.path);
String fileName = pth.basename(imageFile.path);
FirebaseStorage storage = FirebaseStorage.instance;
Reference ref = storage.ref().child("WillyJKT/polaWillyJKT");
UploadTask uploadTask = ref.putFile(imageFile);
uploadTask.whenComplete(() async {
var url = await ref.getDownloadURL();
_image_url = url.toString();
});
FirebaseFirestore.instance
.collection('PolaWillyJKT')
.doc(_selectedOption)
.set({
'Bagian Pola': _selectedOption,
'Kode Pola': _kodePolaController,
'Foto Pola': _image_url
});
}
String _dropdownValue = 'kg';
String _property1 = '';
String _property2 = '';
String _property3 = '';
bool _isOptionSelected = false;
final TextEditingController _kodePolaController = TextEditingController();
var _selectedOption;
final TextEditingController _textfieldValue = TextEditingController();
final List<String> options = [];
#override
void initState() {
super.initState();
_selectedOption = options.isNotEmpty ? options[0] : null;
}
//we can upload image from camera or from gallery based on parameter
Future getImage(ImageSource media) async {
var img = await picker.pickImage(source: media);
setState(() {
image = img;
});
}
void myAlert() {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
title: Text('Please choose media to select'),
content: Container(
height: MediaQuery.of(context).size.height / 6,
child: Column(
children: [
ElevatedButton(
//if user click this button, user can upload image from gallery
onPressed: () {
Navigator.pop(context);
getImage(ImageSource.gallery);
},
child: Row(
children: [
Icon(Icons.image),
Text('From Gallery'),
],
),
),
ElevatedButton(
//if user click this button. user can upload image from camera
onPressed: () {
Navigator.pop(context);
getImage(ImageSource.camera);
},
child: Row(
children: [
Icon(Icons.camera),
Text('From Camera'),
],
),
),
],
),
),
);
});
}
#override
Widget build(BuildContext context) {
final screenHeight = ScreenInfo.screenHeight(context);
final screenWidth = ScreenInfo.screenWidth(context);
return SafeArea(
child: Scaffold(
key: _scaffoldKey,
floatingActionButton: FloatingActionButton(
child: const Icon(Icons.add),
onPressed: () {
_addToFirebase(_dropdownValue, _kodePolaController.text);
},
),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(25),
child: Container(
height: screenHeight,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
TextFormField(
decoration: const InputDecoration(
hintText: 'Input Pola',
border: UnderlineInputBorder(),
),
onChanged: (value) {
setState(() {
_textfieldValue.text = value;
});
},
),
DropdownButton<String>(
value: _selectedOption,
onChanged: (value) {
setState(() {
_selectedOption = value!;
_isOptionSelected = true;
_kodePolaController.clear();
});
},
hint: const Text('Input from Text Field Above'),
items: options.map((option) {
return DropdownMenuItem<String>(
value: option,
child: Text(option),
);
}).toList(),
),
TextButton(
onPressed: _checkDuplicate,
child: const Text("Add Option"),
),
Visibility(
visible: _isOptionSelected,
child: Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
TextField(
controller: _kodePolaController,
decoration: const InputDecoration(
labelText: "Kode Pola"),
onChanged: (value) {
setState(() {
_property1 = value;
});
},
),
const SizedBox(height: 20,),
ElevatedButton(
onPressed: () {
myAlert();
},
child: Text('Upload Photo'),
),
SizedBox(
height: 10,
),
//if image not null show the image
//if image null show text
image != null
? Padding(
padding:
const EdgeInsets.symmetric(horizontal: 20),
child: ClipRRect(
borderRadius: BorderRadius.circular(8),
child: Image.file(
//to show image, you type like this.
File(image!.path),
fit: BoxFit.cover,
width: MediaQuery.of(context).size.width,
height: 300,
),
),
)
: const Text(
"No Image",
style: TextStyle(fontSize: 20),
),
],
),
),
)
],
),
),
),
),
),
);
}
}
It also displays the error on Edge, but when I build the apk and run it on my physical device, it just shows nothing on the screen except for the data that's got above it. Any idea on how I can fix this?
var a = FirebaseFirestore.instance.collection('PolaWillyJKT').get();
This returns a promise but not the actual data. In fact it could still be fetching the data when you attempt to convert it to a map.
You can await
var a = await FirebaseFirestore.instance.collection('PolaWillyJKT').get();
myDoc = a.docs.first();
Or use a callback that will run once the collection fetch completes:
FirebaseFirestore.instance.collection('PolaWillyJKT').get().then((response) => {
print(response);
});
I have a dialog box that sorts a list on my home screen. When I press update the list will sort properly.
What I need to do is run setState for the entire home screen so that the other widgets will reflect the change for the sort order.
Specifically, I have two widgets that I need to rebuild when the update button is pressed.
I have tried to pass a function from the button to the home screen in the constructor and created a function to setState but that didn't work.
Please let me know if I'm being clear enough. Thanks
Home:
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home'),
),
body: SingleChildScrollView(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
SizedBox(
height: 30,
),
HpHeader(),
SizedBox(height: 30),
QuoteBox(),
SizedBox(height: 30),
//parent
MainDebtDebt(),
SizedBox(height: 30),
AdCard(),
//child
AllDebtsCard(),
All debts card (where the button is):
import 'package:debt_zero_2/classes/min_debt_class.dart';
//import 'package:debt_zero_2/classes/icon_class.dart';
import 'package:debt_zero_2/widgets/provider_widget.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:shared_preferences/shared_preferences.dart';
class AllDebtsCard extends StatefulWidget {
#override
_AllDebtsCardState createState() => _AllDebtsCardState();
}
class _AllDebtsCardState extends State<AllDebtsCard> {
int debtValue = 1;
int group;
void setValues() async {
SharedPreferences sharedPrefs = await SharedPreferences.getInstance();
final uid = await Provider.of(context).auth.getUidPref();
final db = Firestore.instance;
setState(() {
sharedPrefs.setInt('sortBySnowOrAva', debtValue);
SetMainDebt().setMainDebt();
});
db
.collection('userPreferences')
.document(uid)
.updateData({'sortBySnowOrAva': debtValue});
}
getValues() async {
SharedPreferences sharedPrefs = await SharedPreferences.getInstance();
int intValue = sharedPrefs.getInt('sortBySnowOrAva');
return intValue;
}
restore() async {
final SharedPreferences sharedPrefs = await SharedPreferences.getInstance();
setState(() {
group = (sharedPrefs.getInt('sortBySnowOrAva') ?? false);
});
}
final dbPath = Firestore.instance.collection('userDebts');
Stream<QuerySnapshot> dbStream(BuildContext context) async* {
final uid = await Provider.of(context).auth.getUidPref();
final intValues = await getValues();
yield* intValues == 1
? dbPath
.document(uid)
.collection('debts')
.orderBy('balance')
.snapshots()
: dbPath
.document(uid)
.collection('debts')
.orderBy('interest', descending: true)
.snapshots();
}
#override
void initState() {
super.initState();
restore();
}
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
RaisedButton(
child: Text('SORT'),
onPressed: () {
showDialog(
barrierDismissible: false,
context: context,
builder: (BuildContext context) {
return StatefulBuilder(
builder: (context, setState) {
return AlertDialog(
title: Text('Sort Debts By:'),
content: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
RadioListTile(
value: 1,
secondary: IconButton(
onPressed: () {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('Debt Snowball:'),
content: Text(
'This is an explanation of debt snowball'),
actions: <Widget>[
FlatButton(
child: Text('OK'),
onPressed: () {
Navigator.pop(context);
},
)
],
);
});
},
icon: Icon(Icons.help_outline),
),
title: Text('Snowball'),
groupValue: group,
onChanged: (T) {
setState(() {
group = T;
debtValue = 1;
});
},
),
RadioListTile(
value: 2,
title: Text('Avalanche'),
secondary: IconButton(
onPressed: () {},
icon: Icon(Icons.help_outline),
),
groupValue: group,
onChanged: (T) {
setState(() {
group = T;
debtValue = 2;
});
},
)
],
),
actions: <Widget>[
FlatButton(
onPressed: () async {
setState(() {
setValues();
});
Navigator.pop(context);
},
child: Text('UPDATE'),
),
FlatButton(
child: Text(
'CANCEL',
style: TextStyle(color: Colors.red),
),
onPressed: () {
Navigator.pop(context);
},
),
],
);
},
);
}).then((value) => setState(() {}));
},
),
StreamBuilder<QuerySnapshot>(
stream: dbStream(context),
builder: (context, snapshot) {
if (snapshot.hasData) {
final debts = snapshot.data.documents;
List<Widget> debtWidgets = [];
for (var debt in debts) {
final debtName = debt.data['name'];
final debtType = debt.data['type'];
final debtBalance = debt.data['balance'];
final debtDue = debt.data['due'].toDate();
final debtWidget = Card(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text('$debtType'),
Text('$debtName'),
Text(DateFormat.MMMd().format(debtDue)),
Text('$debtBalance'),
FlatButton(
child: Text(
'DELETE',
style: TextStyle(color: Colors.red),
),
onPressed: () {
//When I delete a debt I need to update the 'debtMinimum' field in prefs and firestore
},
)
],
),
);
debtWidgets.add(debtWidget);
}
return Column(children: debtWidgets);
}
return Container();
}),
],
);
}
}
One of the two widgets that I need updated:
import 'dart:async';
//import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:debt_zero_2/classes/icon_class.dart';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
class MainDebtDebt extends StatefulWidget {
#override
_MainDebtDebtState createState() => _MainDebtDebtState();
}
class _MainDebtDebtState extends State<MainDebtDebt> {
bool thenum = true;
static DebtModel debtIcons = DebtModel();
bool getGoalType = true;
double balance = 0.0;
String name = '';
String type = '';
int numOfDebts = 0;
double safetyBalance = 0.0;
double mainSnowballOpeningBalance = 0.0;
Future<void> getGoalTypeFlag() async {
final SharedPreferences preferences = await SharedPreferences.getInstance();
final sortBy = preferences.getInt('sortBySnowOrAva');
setState(() {
if (sortBy == 1){
balance = preferences.getDouble('mainDebtFieldSnowball');
type = preferences.getString('mainDebtFieldSnowballType');
name = preferences.getString('mainDebtFieldSnowballName');}
if (sortBy == 2){
balance = preferences.getDouble('mainAvalancheBalance');
type = preferences.getString('mainAvalancheBalanceType');
name = preferences.getString('mainAvalancheBalanceName');
}
mainSnowballOpeningBalance = preferences.getDouble('openingBalance');
safetyBalance = preferences.getDouble('safetyBalance');
getGoalType = preferences.getBool('mainGoalIsDebts');
numOfDebts = preferences.getInt('numberOfDebts');
});
}
#override
void initState() {
super.initState();
getGoalTypeFlag();
}
#override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
decoration: BoxDecoration(border: Border.all()),
child: Column(
children: <Widget>[
Text(getGoalType
? 'I\'m Knocking Out This Payment:'
: 'I\'m Building My Safety Fund'),
SizedBox(
height: 15,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
getGoalType
? debtIcons.getDebtIcon(type)
: '🧯',
style: TextStyle(fontSize: 30),
),
SizedBox(
width: 20,
),
Text(getGoalType ? name : 'Safety Fund'),
],
),
SizedBox(
height: 15,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(getGoalType ? 'Remaining Balance:' : 'Saved:'),
SizedBox(
width: 15,
),
Text(getGoalType
? '\$' + balance.toStringAsFixed(0)
: safetyBalance.toStringAsFixed(0))
],
),
SizedBox(
height: 15,
),
Column(
children: <Widget>[
Text('Current Progress:'),
SizedBox(
height: 10,
),
Container(
decoration: BoxDecoration(border: Border.all()),
height: 22,
width: 202,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Flexible(
child: FractionallySizedBox(
widthFactor: .75,
//fix this
// 1 - mainSnowballBalance / mainSnowballOpeningBalance,
child: Container(
color: Colors.green,
),
),
)
],
),
),
SizedBox(
height: 15,
),
RaisedButton(
child: Text(getGoalType ? 'MAKE A PAYMENT' : 'MAKE A DEPOSIT'),
onPressed: () {
Navigator.of(context).pushNamed('/makePayment');
},
),
SizedBox(
height: 30,
),
RaisedButton(
child: Text('GET DATA'),
onPressed: ()async {
SharedPreferences pref = await SharedPreferences.getInstance();
String thenum = pref.getString('mainAvalancheBalanceType1');
//pref.setBool('isInOb', null);
print(thenum);
},
),
],
)
],
),
);
}
}
I want to fetch the data from API and display it in flutter app. I've been able to fetch the data and display it using ListView builder. But, the problem now I'm facing is that the scroll is not working properly in this case and I don't want to display the data in the form of Lists.
So, is there any other way where we can fetch the data and show it in the app. This is how the UI is going to look.
I'm unable to accomplish this using ListView builder or any other way as I'm very new to flutter.
This is my code which I used in another widget where I was facing the scrolling issue, to create the ListView:
#override
_AllEventsState createState() => _AllEventsState();
}
class _AllEventsState extends State<AllEvents> {
final String url =
"api-url";
List data;
#override
void initState() {
super.initState();
this.getAllEvents();
}
createRoute(id) {
print('args $id');
Navigator.pushNamed(context, '/eventdetail', arguments: id);
}
Future<String> getAllEvents() async {
var response = await http.get(
Uri.encodeFull(url),
headers: {"Accept": "application/json"},
);
setState(() {
var convertDataToJson = jsonDecode(response.body);
data = convertDataToJson["events"];
});
return "Success";
}
#override
Widget build(BuildContext context) {
ScrollController _controller = new ScrollController();
return Container(
child: ListView.builder(
physics: const AlwaysScrollableScrollPhysics(),
controller: _controller,
shrinkWrap: true,
itemCount: data == null ? 0 : data.length,
itemBuilder: (BuildContext cont, int index) {
// format date
var dateString = data[index]["eventDate"];
var eventDate = Jiffy(dateString).MMMEd;
return Container(
padding: const EdgeInsets.fromLTRB(30, 7, 30, 7),
child: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
new InkWell(
onTap: () {
print('card tapped');
createRoute(data[index]['_id']);
},
child: Card(
child: Container(
decoration: BoxDecoration(
border: Border.all(
width: 3,
color: hexToColor("#EBEBEB"),
),
borderRadius: BorderRadius.circular(8.0),
),
padding: const EdgeInsets.fromLTRB(20, 20, 20, 20),
child: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
customText(
eventDate.toString(),
"#000000",
"20.0",
TextAlign.left,
"Roboto Black",
FontWeight.w900,
),
customText(
"10, 9",
"#000000",
"20.0",
TextAlign.right,
"Roboto Black",
FontWeight.w900,
),
],
),
SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Expanded(
child: customText(
"${data[index]['city']} | ${data[index]['arenaName']} | ${data[index]['categories'][0]['title']}",
"#000000",
"18.0",
TextAlign.left,
"Roboto Black",
FontWeight.w900,
),
),
],
),
],
),
),
),
),
],
),
),
);
},
),
);
}
}
This is how I'm fetching the data from the API in another widget:
print("$url${widget.eventId}");
var response = await http.get(
Uri.encodeFull("$url${widget.eventId}"),
// headers: {"Accept": "application/json"},
);
print('events response ${response.body}');
setState(() {
var convertDataToJson = jsonDecode(response.body);
data = convertDataToJson["event"];
print(data);
});
return "Success";
}```
Can you please suggest a way as to how I can display the data properly in flutter?
Use FutureBuilder to get data from api like this :-
FutureBuilder(
future: yourMethodName(),
builder: (context, AsyncSnapshot<NameOfModelClass> snapshot) {
if (snapshot.data == null) {
return Center(child: CircularProgressIndicator());
}
// after getting data from api
},
);
Your method can be like this :
Future<NameOfModelClass> YourMethodName() async {
final response = await http.get('Your url here');
return NameOfModelClass.fromJson(json.decode(response.body.toString()));
}
The model class can be generate by using jsonToDart
I hope this help :)
I want to be able to use shared preferences to grab some boolean value that I save, so I can use that value to set a switch when I first open up that page. The error I am getting is this
type 'Future' is not a subtype of type 'bool'.
I believe what I am getting at the moment is a type Future. What do I need to do to the Future to just get the bool part?
class Settings extends StatefulWidget {
createState() => SettingsState();
}
class SettingsState extends State<Settings> {
getPrefValue(String prefsKey) async {
SharedPreferences.getInstance().then((onValue) {
if(onValue.getBool(prefsKey) == null){
return true;
}
return onValue.getBool(prefsKey);
});
}
var skinOnSwitch = true;
var skinlessSwitch = true;
_saveChickenSelection() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
setState((){
prefs.setBool("skinlessPref", skinlessSwitch);
prefs.setBool("skinPref", skinOnSwitch);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.pink,
body: Container (
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.bottomLeft,
end: Alignment.topRight,
stops: [0.3,0.7],
colors: [Colors.pink[300], Colors.pink[900]]
)
),
child: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Text("SETTINGS",
style: TextStyle(color: Colors.white,fontSize: 40)),
)
],
),
Row(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Text("SKINELESS BONELESS Calculation"),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Switch(
value: getPrefValue("skinlessPref"),
onChanged: (value){
setState(() {
skinlessSwitch = value;
_saveChickenSelection();
});
},
activeTrackColor: Colors.redAccent,
activeColor: Colors.lightGreenAccent,
),
)
],
),
Row(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Text("SKIN ON< BONE ON Calculation"),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Switch(
value: getPrefValue("skinPref"),
onChanged: (value){
setState(() {
skinOnSwitch = value;
_saveChickenSelection();
});
},
activeTrackColor: Colors.redAccent,
activeColor: Colors.lightGreenAccent,
),
)
],
)
],
),
),
);
}
}
Any explanation/help would be most appreciated! Thanks!
I recommend you to rewrite your getPrefValue function to the following:
Future<bool> getPrefValue(String key) async {
final SharedPreferences prefs = await SharedPreferences.getInstance();
return prefs.getBool(key) ?? false;
}
This is more clear on what is happening, the null-aware operator ?? already checks null values.
Then, you can use a FutureBuilder on your widget tree as the other answer says.
You can use a FutureBuilder.
Instead of
Switch(
value: getPrefValue("skinlessPref"),
...
use
FutureBuilder<bool>(
future: getPrefValue("skinlessPref"),
builder: (context, AsyncSnapshot<bool> snapshot) {
if (snapshot.hasData){
return Switch(
value: snapshot.data,
...
}else{
return Container();
}
}
)
You should also change your getPrefValue to:
Future<bool> getPrefValue(String prefsKey) async {
var prefs = await SharedPreferences.getInstance();
if (prefs.getBool(prefsKey) == null){
return true;
}
return prefs.getBool(prefsKey);
}