i am new at flutter, so i tried to implement carousel slider with images, i receive an List with my model from server and i created widget but it shows only 1 item from 18... I mean it always show 1 item, but all list is passed
But if i make hot reload then i receive all items, i hope i could explain... my dart code
import 'dart:convert';
import 'package:carousel_slider/carousel_slider.dart';
import 'package:flutter/material.dart';
import 'package:vltest/Models/_easyloaderslist.dart';
import 'Models/_workers.dart';
import 'Widgets/navigation_drawer_widget.dart';
import 'database.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:http/http.dart' as http;
late List<EasyLoadersList> imgList = List.empty();
class Landing extends StatefulWidget {
#override
_LandingState createState() => _LandingState();
}
Future<List<EasyLoadersList>> _getLoaders(Workers workers) async {
final response = await http.get(
Uri.parse(
'http://url'),
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer ${workers.token}"
});
if (response.statusCode == 200) {
Iterable l = json.decode(response.body);
List<EasyLoadersList> loaders = List<EasyLoadersList>.from(
l.map((model) => EasyLoadersList.fromJson(model)));
return loaders;
} else {
throw Exception('Failed to load album');
}
}
List<T> map<T>(List list, Function handler) {
List<T> result = [];
for (var i = 0; i < list.length; i++) {
result.add(handler(i, list[i]));
}
return result;
}
showWorkerDialog(BuildContext context, Workers album) {
// set up the button
Widget okButton = TextButton(
child: Text("OK"),
onPressed: () {
Navigator.pop(context);
},
);
// set up the AlertDialog
AlertDialog alert = AlertDialog(
title: Text(album.name),
content: Text("Hi, ${album.name}"),
actions: [
okButton,
],
);
// show the dialog
showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
);
}
class _LandingState extends State<Landing> {
String _username = "";
late List<EasyLoadersList> loaders = List.empty();
int _current = 0;
#override
void initState() {
super.initState();
_loadUserInfo();
}
#override
Widget build(BuildContext context) {
return Scaffold(
drawer: NavigationDrawerWidget(),
appBar: AppBar(
title: Text('User info'),
),
body: RefreshIndicator(
onRefresh: () async {
_loadUserInfo();
},
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
CarouselSlider.builder(
itemCount: imgList.length,
itemBuilder: (context, index, realIndex) {
if (imgList.length != 0) {
return buildImage(imgList[index]);
} else {
return loadingData(context);
}
},
options: CarouselOptions(height: 500),
),
]),
),
),
);
}
Widget buildImage(EasyLoadersList loadersList) => Column(
mainAxisSize: MainAxisSize.max,
children: [
AspectRatio(
aspectRatio: 1,
child: Image.network(
loadersList.url,
fit: BoxFit.fill,
),
),
const SizedBox(
height: 30,
),
Text("Address :" + loadersList.shopAddress),
Text("Serial:" + loadersList.serialNumber),
Text("Hours :" + loadersList.currentMotoHours),
Text("Current:" + loadersList.currentMotoHoursUntilTO),
Text("Next:" + loadersList.remainsMotoHoursUntilTO),
Text("Last Use:" + loadersList.lastMotoHoursEditDate),
],
);
Widget loadingData(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Text(
'Loading...',
style: Theme.of(context).textTheme.headline6,
),
CircularProgressIndicator(
semanticsLabel: 'Loading...',
),
],
),
),
);
}
Future<void> _loadUserInfo() async {
Workers workers = await DBProvider.db.getWorkerInfo();
final prefs = await SharedPreferences.getInstance();
showWorkerDialog(context, workers);
imgList = await _getLoaders(workers);
}
}
Cant see any setState to update the UI. try adding setState on end of refresh like.
onRefresh: () async {
await _loadUserInfo();
setState((){});
},
And on initState
_loadUserInfo().then((value) {setState((){})}):
Or
Future<void> _loadUserInfo() async {
.....
imgList = await _getLoaders(workers);
setState((){});
}
Related
I am trying to add a search function in my flutter app, the search bar is showing and there's not errors but its not working and it doesn't return any results.
the data list is from an API that I already called using the rest API
// ignore_for_file: use_key_in_widget_constructors, avoid_print, avoid_unnecessary_containers, curly_braces_in_flow_control_structures, prefer_const_constructors, non_constant_identifier_names, unnecessary_new, avoid_function_literals_in_foreach_calls, unused_import, avoid_types_as_parameter_names, unused_label
import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:myapp2/Service_Request/SR.dart';
import 'package:myapp2/main.dart';
import 'package:myapp2/Service_Request/second.dart';
import '../Classes/demandes.dart';
import 'SR_details.dart';
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: DataFromAPI(),
);
}
}
class DataFromAPI extends StatefulWidget {
#override
_DataFromAPIState createState() => _DataFromAPIState();
}
List<Attributes> _MyAllData = [];
var _srAttributes = [];
class _DataFromAPIState extends State<DataFromAPI> {
#override
void initState() {
loadData().then((value) {
setState(() {
_srAttributes.addAll(value);
});
});
super.initState();
}
Future<List<Sr>> loadData() async {
try {
var response = await http.get(Uri.parse(
'http://192.168.1.30:9080/maxrest/rest/mbo/sr/?_lid=azizl&_lpwd=max12345m&_format=json'));
if (response.statusCode == 200) {
final jsonBody = json.decode(response.body);
Demandes data = Demandes.fromJson(jsonBody);
final srAttributes = data.srMboSet.sr;
return srAttributes;
}
} catch (e) {
throw Exception(e.toString());
}
throw Exception("");
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: new Scaffold(
appBar: AppBar(
title: Text('Liste des Demandes'),
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () => Navigator.push(
context, MaterialPageRoute(builder: (context) => SR()))),
),
body: FutureBuilder<List<Sr>?>(
future: loadData(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return CircularProgressIndicator();
} else {
return new ListView.builder(
itemCount: snapshot.data?.length,
itemBuilder: ((_, index) {
return index == 0
? _searchbar()
: new ListTile(
title: new Card(
margin: new EdgeInsets.symmetric(
vertical: 2.0, horizontal: 8.0),
elevation: 10,
child: new ListTile(
title: new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(padding: new EdgeInsets.all(2.0)),
new Text(
'Ticket ID : ${snapshot.data![index].attributes.ticketid.content}'),
new Text(
'status : ${snapshot.data![index].attributes.status.content}'),
new Text(
'description : ${snapshot.data![index].attributes.description?.content}'),
new Text(
'Reported by : ${snapshot.data![index].attributes.reportedby.content}'),
new Text(
'Reoprt date : ${snapshot.data![index].attributes.statusdate.content}'),
],
),
trailing: Icon(Icons.arrow_forward_ios_rounded),
),
),
onTap: () {
Navigator.of(context)
.push(
new MaterialPageRoute(
builder: (BuildContext context) =>
new SrDetailsScreen(
sr: snapshot.data![index]),
),
)
.then((data) {});
});
}),
);
}
},
),
),
);
}
_searchbar() {
return Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
decoration: InputDecoration(hintText: "Search ..."),
onChanged: (text) {
text = text.toLowerCase();
setState(() {
_srAttributes = _MyAllData.where((srAttributes) {
var idticket = srAttributes.description!.content.toLowerCase();
return idticket.contains(text);
}).toList();
});
},
),
);
}
}
FutureBuilder loads values of current future. You are assigning a function result to FutureBuilder so its value always changes dynamically.
Create variable to keep Future's value.
Future<List<Sr>>? dataToLoad;
Whenever you want to load data from server ( for example, on text changed ):
setState((){
dataToLoad = loadData();
});
And use it in FutureBuilder:
FutureBuilder<List<Sr>?>(
future: dataToLoad,
i'm trying to set the login cookies to the rest of the get requests.
so i use http pachakge and store the login cookies with sharedPreferences and use it in the get request by adding an update function
but i have a problem that when i go to the page i get 400 response just refreshing the page and i get my data and response 200
is there any other solution for setting cookies in the others get requests headers ?
or is there a solution for my bug ?
codes images : [https://ibb.co/kD3dDc9]
[https://ibb.co/25p5fZr]
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:shared_preferences/shared_preferences.dart';
import 'package:valomnia_reports/Screens/Superviseur%20Screens/SideBar.dart';
import 'user_model.dart';
class SellersPage extends StatefulWidget {
const SellersPage({Key? key}) : super(key: key);
#override
_SellersPage createState() => _SellersPage();
}
class _SellersPage extends State<SellersPage> {
String? finalEmail;
Future? _futureData;
String? rawCookie;
// ignore: must_call_super
void initState() {
getValidationData();
super.initState();
_futureData = getUserApi();
}
Future getValidationData() async {
final SharedPreferences sharedPreferences2 =
await SharedPreferences.getInstance();
var obtainedEmail2 = sharedPreferences2.getString("rawCookie");
setState(() {
rawCookie = obtainedEmail2;
print(rawCookie);
});
}
List<UserModel> userList = [];
Map<String, String> headers = {};
Future<List<UserModel>> getUserApi() async {
http.Response response = await http.get(
Uri.parse('https://valomnia.herokuapp.com/superviseur/getAllVendeurs'),
headers: headers);
response.headers['set-cookie'] = rawCookie!;
updateCookie(response);
var data = jsonDecode(response.body.toString());
String? cookies = response.headers['set-cookie'];
if (response.statusCode == 200) {
for (Map i in data) {
userList.add(UserModel.fromJson(i));
}
print("Cookie : $cookies");
print("200");
return userList;
} else {
print("400");
print(rawCookie);
print(cookies);
return userList;
}
}
void updateCookie(http.Response response) {
String? rawCookie2 = response.headers['set-cookie'];
if (rawCookie2 != null) {
int index = rawCookie2.indexOf(';');
headers['cookie'] =
(index == -1) ? rawCookie2 : rawCookie2.substring(0, index);
}
}
final GlobalKey<RefreshIndicatorState> _refreshIndicatorKey =
new GlobalKey<RefreshIndicatorState>();
Future<Null> _refresh() {
return getUserApi().then((userList) {
setState(() => userList = userList);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
drawer: NavigationDrawerWidget(),
appBar: AppBar(
title: Text(
'Sellers list',
),
centerTitle: true,
backgroundColor: Colors.green,
),
body: Column(
children: [
Expanded(
child: FutureBuilder(
future: _futureData,
builder: (context, AsyncSnapshot snapshot) {
if (!snapshot.hasData) {
return Center(child: CircularProgressIndicator());
} else {
return RefreshIndicator(
key: _refreshIndicatorKey,
onRefresh: _refresh,
child: ListView.builder(
itemCount: userList.length,
itemBuilder: (context, index) {
return Card(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
ReusbaleRow(
title: 'Id',
value:
snapshot.data![index].id.toString()),
ReusbaleRow(
title: 'Name',
value: snapshot.data![index].name
.toString()),
ReusbaleRow(
title: 'Username',
value: snapshot.data![index].username
.toString()),
ReusbaleRow(
title: 'DateCreated',
value: snapshot.data![index].email
.toString()),
],
),
),
);
}),
);
}
},
),
)
],
),
);
}
}
// ignore: must_be_immutable
class ReusbaleRow extends StatelessWidget {
String title, value;
ReusbaleRow({Key? key, required this.title, required this.value})
: super(key: key);
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(title),
Text(value),
],
),
);
}
} ```
I want to access data from the API below.
"https://api.categen.com/api.php/recent_activity/1"
and Want to print in text.
Please help me.
Moreover, there is 3 classes
Home . dart file.
DataService . dart file.
Model . dart file
I tried below code.
Home.dart .
import 'dart:convert';
import 'package:categen_api_test/data_service.dart';
import 'package:categen_api_test/model.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
final _dataService = DataService();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Categen API"),
),
body: Center(
child: ElevatedButton(
child: Text("Click me"),
onPressed: () {
_getlist();
},
),
),
);
}
void _getlist() async {
final response = await _dataService.getData();
print(response.name);
}
}
DataService
import 'dart:convert';
import 'package:categen_api_test/model.dart';
import 'package:http/http.dart' as http;
class DataService {
Future<ModelData> getData() async {
final String url = "https://api.categen.com/api.php/recent_activity/1";
final uri = Uri.https('api.categen.com', '/api.php/recent_activity/1');
final response = await http.get(uri);
print(response.body);
final json = jsonDecode(response.body);
return ModelData.fromJson(json);
}
}
First create a model like this:
class Model {
final String name;
final String location;
final String action_value;
final String item;
Model(this.name, this.location, this.action_value, this.item);
List<Model> getList(json) {
List<Model> tempList = []
json['records'].forEach((model)=> tempList.add(
Model(
model["name"],
model["location"],
model["action_value"],
model["item"]
)
)
);
return tempList;
}
}
Then create a function to fetch the data:
Future<List<Model>> fetchData() async {
final response = await http.get('https://api.categen.com/api.php/recent_activity/1');
if (response.statusCode == 200) {
return Model.getList(response.body);
} else {
throw Exception('Unable to fetch products from the REST API');
}
}
call the fetch data function in the init state of the HomePage Widget
late Future<List<Model>> futureData;
void initState() {
super.initState();
futureData = fetchData();
}
what is left to do now is to get your data using a FutureBuilder Widget.
and display the list of your data
FutureBuilder<Model>(
future: futureData,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Column(
children: snaphot.map((e)=>Text(e.name)).toList()
);
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
}
return const CircularProgressIndicator();
},
)
if you want to reload the data on the click of a button, then call the fetch data whenever the button is clicked and then rebuild state of the Homepage widget like shown below
onPressed: (){
setState(
(){
futureData = fetchData();
}
);
}
Try below code hope its helpful to you. If you get data from API refer my answer here or here or here hope it's helpful to you
Create your home widget:
Center(
child: ElevatedButton(
child: Text('Pressed Me'),
onPressed: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Jobs(),
),
),
),
),
Create your List Widget.
Your API Call function:
Future<List<dynamic>> getJobsData() async {
String url = 'https://api.categen.com/api.php/recent_activity/1';
var response = await http.get(Uri.parse(url), headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
});
return json.decode(response.body)['records'];
}
Your Widget:
Column(
children: [
Expanded(
child: Center(
child: FutureBuilder<List<dynamic>>(
future: getJobsData(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: ListView.builder(
itemCount: snapshot.data!.length,
itemBuilder: (context, index) {
var name = snapshot.data![index]['name'];
var location = snapshot.data![index]['location'];
var item = snapshot.data![index]['item'];
var action = snapshot.data![index]['action_value'];
var date = snapshot.data![index]['created_timestamp'];
return Card(
shape: RoundedRectangleBorder(
side: BorderSide(color: Colors.green.shade300),
borderRadius: BorderRadius.circular(15.0),
),
child: ListTile(
leading: Text(
action.toString(),
),
title: Text(name),
subtitle: Text(
location + '\n' + date,
),
trailing: Text(item),
),
);
},
),
);
}
return CircularProgressIndicator();
},
),
),
),
],
),
Your all class:
class Jobs extends StatelessWidget {
Future<List<dynamic>> getJobsData() async {
String url = 'https://api.categen.com/api.php/recent_activity/1';
var response = await http.get(Uri.parse(url), headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
});
return json.decode(response.body)['records'];
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Jobs'),
),
body: Column(
children: [
Expanded(
child: Center(
child: FutureBuilder<List<dynamic>>(
future: getJobsData(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: ListView.builder(
itemCount: snapshot.data!.length,
itemBuilder: (context, index) {
var name = snapshot.data![index]['name'];
var location = snapshot.data![index]['location'];
var item = snapshot.data![index]['item'];
var action = snapshot.data![index]['action_value'];
var date = snapshot.data![index]['created_timestamp'];
return Card(
shape: RoundedRectangleBorder(
side: BorderSide(color: Colors.green.shade300),
borderRadius: BorderRadius.circular(15.0),
),
child: ListTile(
leading: Text(
action.toString(),
),
title: Text(name),
subtitle: Text(
location + '\n' + date,
),
trailing: Text(item),
),
);
},
),
);
}
return CircularProgressIndicator();
},
),
),
),
],
),
);
}
}
Your Home widget output screen->
Your List Widget output screen->
I added a popup window (alertdialog) into my flutter project which has a streambuilder. It didnt work at first but after making it async and adding a code like below
await Future.delayed(Duration(milliseconds: 50));
It started to work fine. This popup would occur after a specific data changes in the database. Later i wanted to add a second popup window to my project for a second database value, the difference is this one has a text field for user input and offcourse a controller for this. When i tried this one popup worked fine but at the back of the popup it gave
type 'Future<dynamic>' is not a subtype of type 'Widget'
error with red/yellow error background. The difference between these 2 popups are as i said one of them has controller for input, what i am doing wrong here?
Here is the full code:
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:assets_audio_player/assets_audio_player.dart';
import 'package:flutter/scheduler.dart';
import 'numbers.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:sayi_avi/homescreen.dart';
Numbers myNumbers = Numbers();
void main(){
runApp(
GameScreen()
);
}
class GameScreen extends StatefulWidget {
static String id ='gamescreen';
#override
_GameScreenState createState() => _GameScreenState();
}
class _GameScreenState extends State<GameScreen> {
bool _initialized = false;
bool _error = false;
TextEditingController _controller;
void initializeFlutterFire() async {
try {
// Wait for Firebase to initialize and set `_initialized` state to true
await Firebase.initializeApp();
setState(() {
_initialized = true;
});
} catch(e) {
// Set `_error` state to true if Firebase initialization fails
setState(() {
_error = true;
});
}
}
#override
void initState() {
initializeFlutterFire();
super.initState();
getCurrentUser();
_controller = TextEditingController();
}
void dispose() {
_controller.dispose();
super.dispose();
}
final _auth =FirebaseAuth.instance;
User loggedInUser;
final _firestore = FirebaseFirestore.instance;
final String collectionPath = 'users';
String docPath;
var userPath;
DocumentReference userdoc;
var userSnapshot;
String gameResult;
String sendednumber='';
List<dynamic> kullanicisayilari = [];
List<dynamic> rakipsayilari = [];
List<dynamic> sonuc = [];
void getCurrentUser() async{
try{
final user = await _auth.currentUser;
if(user !=null){
loggedInUser =user;
docPath = loggedInUser.uid;
userPath = _firestore.collection(collectionPath);
userdoc = userPath.doc(docPath);
userSnapshot = userdoc.snapshots();
}
}catch(e){
print(e);
}
}
Expanded attachNumber(number,imagenumber){
return Expanded(
child:FlatButton(
onPressed: (){
setState(() {
if(!myNumbers.numberStatus[1]){
myNumbers.buttonValues['numberimage1'] = imagenumber;
myNumbers.numberStatus[1] =true;
myNumbers.decimals[1]=number;
}else if(!myNumbers.numberStatus[2]){
myNumbers.buttonValues['numberimage2'] = imagenumber;
myNumbers.numberStatus[2] =true;
myNumbers.decimals[2]=number;
}else if(!myNumbers.numberStatus[3]){
myNumbers.buttonValues['numberimage3'] = imagenumber;
myNumbers.numberStatus[3] =true;
myNumbers.decimals[3]=number;
}else if(!myNumbers.numberStatus[4]){
myNumbers.buttonValues['numberimage4'] = imagenumber;
myNumbers.numberStatus[4] =true;
myNumbers.decimals[4]=number;
}
});
final assetsAudioPlayer = AssetsAudioPlayer();
assetsAudioPlayer.open(
Audio("assets/audios/click.wav"),
);
},
padding: EdgeInsets.all(0),
child: Image.asset('images/$imagenumber'),
),
);
}
Expanded showDeleteNumbers(statusNumber,number){
return Expanded(
child:FlatButton(
onPressed: (){
setState(() {
myNumbers.decimals[statusNumber]='';
myNumbers.numberStatus[statusNumber] =false;
myNumbers.buttonValues[number] = 'nonumber.png';
});
},
child: Image.asset('images/'+myNumbers.buttonValues['$number']),
),
);
}
Future<void> sendnumber() {
sendednumber="";
for (var numbers in myNumbers.decimals.values){
sendednumber = sendednumber+numbers;
}
Random rnd;
int min = 10000;
int max = 100000;
rnd = new Random();
var r = min + rnd.nextInt(max - min);
kullanicisayilari.add(sendednumber+"|"+r.toString());
return userPath
.doc(docPath)
.update({'atilansayi': kullanicisayilari})
.then((value) => print("User Updated"))
.catchError((error) => print("Failed to update user: $error"));
}
/*
List<Widget> getUserNumbers(){
return
}
*/
Text getUserNumbers(kullanicisayilari){
for(var number in kullanicisayilari){
return Text(number);
};
}
//This one is working fine
_showMaterialDialog(String type) async{
if(type=="win"){
gameResult = "You Win, Gratz!";
}else if(type=="lose"){
gameResult = "You Lose :(";
}
print("buraya girdi");
print(gameResult);
await Future.delayed(Duration(milliseconds: 50));
showDialog (
context: context,
builder: (_) => AlertDialog(
title: Text("Result"),
content: Text(gameResult),
actions: <Widget>[
FlatButton(
child: Text('Close'),
onPressed: () {
Navigator.pushNamed(context, HomeScreen.id);
},
)
],
));
}
//This one is causing errors
_showMaterialDialogNumber() async{
await Future.delayed(Duration(milliseconds: 100));
showDialog (
context: context,
builder: (_) => AlertDialog(
title: Text("Start"),
content: TextField(
controller: _controller,
obscureText: true,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Enter your Number',
),
),
actions: <Widget>[
FlatButton(
child: Text('Submit'),
onPressed: () {
Navigator.of(context).pop();
},
)
],
));
}
/*
*/
#override
Widget build(BuildContext context) {
if(_error) {
return Text('error-game', textDirection: TextDirection.ltr);
}
// Show a loader until FlutterFire is initialized
if (!_initialized) {
return Text('Loading', textDirection: TextDirection.ltr);
}
return StreamBuilder<DocumentSnapshot>(
stream: userSnapshot,
builder: (BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {
if (snapshot.hasError) {
return Text('Something went wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Text("Loading");
}
if(snapshot.hasData){
Map<String, dynamic> userDocument = snapshot.data.data();
print(collectionPath);
print(docPath);
print(snapshot.data);
print(userDocument);
gameResult = userDocument['status'];
//This one works fine
if(gameResult =="win" || gameResult =="lose"){
return _showMaterialDialog(gameResult);
}
//This one causing errors
if(gameResult=="on"){
return _showMaterialDialogNumber();
}
kullanicisayilari = userDocument['atilansayi'];
List<dynamic> kullanicisayilariDuz = [];
List<dynamic> rakipsayilariDuz = [];
List<dynamic> sonuclarDuz = [];
for (var numbers in kullanicisayilari){
var splittedNumber = numbers.split('|');
kullanicisayilariDuz.add(splittedNumber[0]);
}
rakipsayilari = userDocument['rakipsallama'];
sonuc = userDocument['sonuc'];
for (var sonuclar in sonuc){
var splittedSonuc = sonuclar.split('|');
sonuclarDuz.add(splittedSonuc[0]);
}
for (var rakipsayi in rakipsayilari){
var splittedRakipSayi = rakipsayi.split('|');
rakipsayilariDuz.add(splittedRakipSayi[0]);
}
print(myNumbers.decimals);
return MaterialApp(
home:Scaffold(
appBar: AppBar(
backgroundColor: Colors.amberAccent,
title: Text('Sayı Avı Oyun Ekranı'),
),
body:Column(
children: <Widget>[
Expanded(
flex: 80,
child: Row(
children: <Widget>[
Expanded(
flex: 40,
child: Column(
children: <Widget>[
for(var numbers in kullanicisayilariDuz)Text(numbers),
]
),
),
Expanded(
flex: 10,
child: Column(
children: <Widget>[
for(var numbers in sonuclarDuz)Text(numbers),
]
),
),
Expanded(
flex: 50,
child: Column(
children: <Widget>[
for(var numbers in rakipsayilariDuz)Text(numbers),
]
),
),
],
),
),
Expanded(
flex:10,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
showDeleteNumbers(1,'numberimage1'),
showDeleteNumbers(2,'numberimage2'),
showDeleteNumbers(3,'numberimage3'),
showDeleteNumbers(4,'numberimage4'),
Expanded(
child:FlatButton(
onPressed: (){
sendnumber();
},
child: Image.asset('images/send.png'),
),
),
],
),
),
Expanded(
flex: 10,
child: Row(
children: <Widget>[
attachNumber('1','one.png'),
attachNumber('2','two.png'),
attachNumber('3','three.png'),
attachNumber('4','four.png'),
attachNumber('5','five.png'),
attachNumber('6','six.png'),
attachNumber('7','seven.png'),
attachNumber('8','eight.png'),
attachNumber('9','nine.png'),
attachNumber('0','zero.png'),
],
),
),
],
),
),
);
}
},
);
}
}
Thanks in advance.
The build function of your GameScreen needs to return a Widget:
Widget build(...) {}
However, when you display the dialogs, you do:
return _showMaterialDialog();
This dialogs function returns a Future<> which can not be a Widget. This explains the error.
I would prefer to declare them explicitly and they should return the dialogs inside the async function, as follows:
Future _showMaterialDialog() async {
...
return showDialog(...);
}
By the way, using the same context passing into the parameter of the funtion should be better:
Future _showMaterialDialog(BuildContext context) {
// use the local 'context' to build the dialog
}
Finally, in order to correctly use these dialogs, just show them and return at last a Widget:
if (...) {
_showMaterialDialog(context);
}
return MaterialApp(...);
And, you don't need the two delayed you added, if you let the time of the UI to be displayed.
Indeed, because of using a StreamBuilder, the UI is not displayed yet, you need to wait when the main rendering pipeline has been flushed by using addPostFrameCallback:
WidgetsBinding.instance.addPostFrameCallback((_) {
_showMaterialDialog(context);
}
PS: remember that Flutter is all Widgets, consider to refacto your code into small Widgets to avoid doing a lot of stuffs into one class only.
I am using a streambuilder for listening changes from firestore database and updating my widget. However my problem is i am using a few manual setstates to make visual changes in my code when a button is pressed and these setstates also triggers streambuilder's setstate and shows an extra loading screen to the users. How can i get seperate setstates? Should i use something else instead of streambuilder?
My code is below:
import 'package:flutter/material.dart';
import 'package:assets_audio_player/assets_audio_player.dart';
import 'numbers.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_core/firebase_core.dart';
Numbers myNumbers = Numbers();
void main(){
runApp(
GameScreen()
);
}
class GameScreen extends StatefulWidget {
static String id ='gamescreen';
#override
_GameScreenState createState() => _GameScreenState();
}
class _GameScreenState extends State<GameScreen> {
bool _initialized = false;
bool _error = false;
void initializeFlutterFire() async {
try {
// Wait for Firebase to initialize and set `_initialized` state to true
await Firebase.initializeApp();
setState(() {
_initialized = true;
});
} catch(e) {
// Set `_error` state to true if Firebase initialization fails
setState(() {
_error = true;
});
}
}
#override
void initState() {
initializeFlutterFire();
super.initState();
getCurrentUser();
}
final _auth =FirebaseAuth.instance;
User loggedInUser;
final _firestore = FirebaseFirestore.instance;
final String collectionPath = 'users';
String docPath;
DocumentReference userdoc;
void getCurrentUser() async{
try{
final user = await _auth.currentUser;
if(user !=null){
loggedInUser =user;
docPath = loggedInUser.uid;
}
}catch(e){
print(e);
}
}
Expanded attachNumber(imagenumber){
return Expanded(
child:FlatButton(
onPressed: (){
setState(() {
if(!myNumbers.numberStatus[1]){
myNumbers.buttonValues['numberimage1'] = imagenumber;
myNumbers.numberStatus[1] =true;
}else if(!myNumbers.numberStatus[2]){
myNumbers.buttonValues['numberimage2'] = imagenumber;
myNumbers.numberStatus[2] =true;
}else if(!myNumbers.numberStatus[3]){
myNumbers.buttonValues['numberimage3'] = imagenumber;
myNumbers.numberStatus[3] =true;
}else if(!myNumbers.numberStatus[4]){
myNumbers.buttonValues['numberimage4'] = imagenumber;
myNumbers.numberStatus[4] =true;
}
});
final assetsAudioPlayer = AssetsAudioPlayer();
assetsAudioPlayer.open(
Audio("assets/audios/click.wav"),
);
},
padding: EdgeInsets.all(0),
child: Image.asset('images/$imagenumber'),
),
);
}
FlatButton showDeleteNumbers(statusNumber,number){
return FlatButton(
onPressed: (){
setState(() {
myNumbers.numberStatus[statusNumber] =false;
myNumbers.buttonValues[number] = 'nonumber.png';
});
},
child: Image.asset('images/'+myNumbers.buttonValues['$number']),
);
}
#override
Widget build(BuildContext context) {
userdoc = _firestore.collection(collectionPath).doc(docPath);
if(_error) {
return Text('error-game', textDirection: TextDirection.ltr);
}
// Show a loader until FlutterFire is initialized
if (!_initialized) {
return Text('Loading', textDirection: TextDirection.ltr);
}
return StreamBuilder<DocumentSnapshot>(
stream: userdoc.snapshots(),
builder: (BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {
if (snapshot.hasError) {
return Text('Something went wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Text("Loading");
}
if(snapshot.hasData){
Map<String, dynamic> userDocument = snapshot.data.data();
print(collectionPath);
print(docPath);
print(snapshot.data);
print(userDocument);
return MaterialApp(
home:Scaffold(
appBar: AppBar(
backgroundColor: Colors.amberAccent,
title: Text('Sayı Avı Oyun Ekranı'),
),
body:Column(
children: <Widget>[
Expanded(
flex: 80,
child: Row(
children: <Widget>[
Expanded(
flex: 50,
child: Column(
children: myNumbers.getUserNumbers(),
),
),
Expanded(
flex: 50,
child: Column(
children: myNumbers.getOpponentNumbers(),
),
),
],
),
),
Expanded(
flex:10,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
showDeleteNumbers(1,'numberimage1'),
showDeleteNumbers(2,'numberimage2'),
showDeleteNumbers(3,'numberimage3'),
showDeleteNumbers(4,'numberimage4'),
],
),
),
Expanded(
flex: 10,
child: Row(
children: <Widget>[
attachNumber('one.png'),
attachNumber('two.png'),
attachNumber('three.png'),
attachNumber('four.png'),
attachNumber('five.png'),
attachNumber('six.png'),
attachNumber('seven.png'),
attachNumber('eight.png'),
attachNumber('nine.png'),
attachNumber('zero.png'),
],
),
),
],
),
),
);
}
},
);
}
}
Try capturing the stream userdoc.snapshots() in a variable in initState instead of calling the snapshots method in every build.
That way you make sure that the streambuilder gets the same stream on every build and thus can maintain its state if you rebuild it