How to display an alert message if there is no data flutter - flutter

I am doing a query about the data from a mysql database and they are displayed in a list.
My problem is if there is no data in the database. I would like to display an alert message stating that or display a text to warn that there is no available data.
This is the code page that I use to display the data:
void main() {
runApp(Your()
);
}
class Your extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<Your> {
MyPreferences _myPreferences = MyPreferences();
String apiURL;
var id;
List<Flowerdata> _flowersDataForTheListView = List<Flowerdata>();
Future<List<Flowerdata>> fetchNotes() async {
id=_myPreferences.id;
final String url = 'https://=============/All.php?id=' + id.toString();
var response = await http.get(url);
var flowers = List<Flowerdata>();
if (response.statusCode == 200) {
var flowersJsonData = json.decode(response.body);
for (var flower in flowersJsonData) {
flowers.add(Flowerdata.fromJson(flower));
}
}
else{
}
return flowers;
}
#override
void initState() {
fetchNotes();
super.initState();
}
#override
Widget build(BuildContext context) {
return ListView.builder(
itemBuilder: (context, index) {
return _listItem(index);
},
);
}
_listItem(index) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
children: [
Flexible(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text( _flowersDataForTheListView[index].Name,style: TextStyle(fontSize: 17)),
SizedBox(height: 5.0,),
],
),
),
],
),
],
);
}
}
PHP contact page:
<?php
include 'connt.php';
$id=$_GET['id'];
$sql = "SELECT * FROM user WHERE id=? ORDER BY id DESC";
$stmt = $con->prepare($sql);
$stmt->bind_param("s",$id);
$stmt->execute();
$result = $stmt->get_result();
//$result = $con->query($sql);
if ($result->num_rows >0) {
while($row[] = $result->fetch_assoc()) {
$item = $row;
$json = json_encode($item, JSON_NUMERIC_CHECK);
}
} else {
echo "No";
}
echo $json;
$con->close();
?>
How can I do this if someone knows please help me.

You don't seem to be using MaterialApp in your flutter code, but if you use it, Scaffold widget has a method called showSnackbar where you can display a message that pops up at the bottom of the page.
Here is a sample code for showSnackbar:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: HomePage(),
);
}
}
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: MyList(),
);
}
}
class MyList extends StatefulWidget {
#override
_MyListState createState() => _MyListState();
}
class _MyListState extends State<MyList> {
#override
Widget build(BuildContext context) {
return Container();
}
#override
void initState() {
fetchNotes();
super.initState();
}
Future<void> fetchNotes() async {
// Here, you actually fetch the data from API
await Future.delayed(Duration(seconds: 3));
final flowers = [];
if (flowers.isEmpty) {
Scaffold.of(context).showSnackBar(
SnackBar(
content: Text('Data is empty'),
),
);
}
}
}

Related

How to call function in another state without initializing its class in Flutter?

I'm writing a language learning app and I'm stuck. What am I trying to do is when user pressed the next button, I want to increase the index and show other page in lesson.dart. I have many pages like listening, video etc.
And I want to call nextPage() without initialize Lesson class.
create_word.dart
class CreateWord extends StatefulWidget {
var pathToPlay = '';
String word = '';
String sentence = '';
CreateWord(this.pathToPlay, this.word, this.sentence);
#override
_CreateWordState createState() => _CreateWordState();
}
class _CreateWordState extends State<CreateWord> {
late AudioPlayer player;
#override
void initState() {
super.initState();
player = AudioPlayer();
}
#override
void dispose() {
player.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Center(
child: Column(
children: [
Row(
children: [
// When pressed this button, call nextPage() in lesson.dart
ElevatedButton(
child: Text("Play Sound", style: TextStyle(color: Colors.white, fontSize: 13),),
onPressed: () async{
await player.setAsset(widget.pathToPlay);
player.play();
},
), // The Button
Text(widget.word),
Text(widget.sentence)
],
),
],
),
);
}
}
lesson.dart
class Lesson extends StatefulWidget {
int lesson_index = 0;
Lesson(this.lesson_index);
#override
LessonState createState() => LessonState();
}
class LessonState extends State<Lesson> {
final lessonKey = GlobalKey<LessonState>();
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xff413250),
appBar: buildAppBar(),
body: buildBody(),
//bottomNavigationBar: buildNavbar(),
);
}
late int _lesson_index = widget.lesson_index;
int _page_index = 0;
Widget setLesson(){
var page = data[_lesson_index]['pages'][_page_index];
//switch("video"){
switch(data.isNotEmpty ? page['type'] : null){
case "text":
return Text("Text");
case "video":
return CreateVideo(page['path']);
case "word":
return CreateWord(page['path'], page['word'], page['sentence']);
case "audio_match":
return CreateAudioMatch(page['answers'], page['text'], page['correct_answer_index'], page['complete']);
case "complete_text":
return CreateCompleteText(page['text'], page['answer'], page['complete']);
default:
return Text("Bir hata oluştu. " + page.toString());
}
}
// Call this when button pressed in
void nextPage(){
setState(() {
_page_index < data[_lesson_index]['pages'].length - 1 ? _page_index++ : null;
});
}
}
You can do you function static
static nextPage...
and then get it from anywhere, like this:
Lesson.nextPage

Delete specific widget | Flutter & Riverpod

As shown in the image, I'm trying to have a list of dice where I can add or delete a die. I've tried StateProvider, ChangeNotifier, and StateNotifier. Each one doesn't seem to work as I expect it to. I'm trying to make a provider that contains a list of dieWidgets, but I can't figure out how to remove a specific die when I longpress on it. The image shows a popup menu to delete it, that's the long-term goal, but just a longpress delete would be good for now. Thoughts on how to approach this?
Code
main.dart
class DiceNotifier extends ChangeNotifier {
List<DieWidget> dice = [];
void add() {
dice.add(DieWidget());
notifyListeners();
}
void removeDie(int id) {
// FIXME: Unable to delete a die based on id
print(id);
notifyListeners();
}
}
final diceProvider = ChangeNotifierProvider((_) {
return DiceNotifier();
});
class MyHomePage extends ConsumerWidget {
#override
Widget build(BuildContext context, ScopedReader watch) {
final dice = watch(diceProvider).dice;
return Scaffold(
appBar: AppBar(
title: Text("Dice"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
...dice,
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
context.read(diceProvider).add();
},
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
die_widget.dart
class DieWidget extends StatefulWidget {
#override
_DieWidgetState createState() => _DieWidgetState();
}
class _DieWidgetState extends State<DieWidget> {
int value = 0;
int id = 0;
#override
Widget build(BuildContext context) {
return FlatButton(
child: Text(
'$value',
),
onPressed: () {
setState(() {
value++;
id++;
});
// context.read(dieProvider).increment();
},
onLongPress: () {
final dice = context.read(diceProvider);
dice.removeDie(id);
// print(this.value);
},
);
}
}
One solution would be to define a parameter value in the DiceWidget class:
class DiceWidget extends StatefulWidget {
const DiceWidget({ Key key, this.value }) : super(key: key);
int value;
#override
_DiceWidgetState createState() => _DiceWidgetState();
}
And access this data from the DiceWidget:
class DiceWidget extends StatefulWidget {
#override
_DiceWidgetState createState() => _DiceWidgetState();
}
class _DiceWidgetState extends State<DiceWidget> {
#override
Widget build(BuildContext context) {
return FlatButton(
child: Text(
widget.value.toString() ?? '',
),
onLongPress: () {
final dice = context.read(diceProvider);
dice.removeDice(widget.value);
// print(widget.value);
},
);
}
}
In the DiceNotifier class, I'd recommend to implement the dices array as a List<int>:
List<int> dices = [];
Therefore, the addDice() and removeDice() functions will be, respectively:
class DiceNotifier extends ChangeNotifier {
List<int> dices = [];
void addDice() {
dices.add(dices.length);
notifyListeners();
}
void removeDice(int id) {
dices.remove(id);
print(id);
notifyListeners();
}
}
To make the example work, we need to modify the MyHomePage Column children as well, to build the list of DiceWidgets:
...dices.map((d) => DiceWidget(value: d)).toList(),
The whole example will then be:
main.dart:
class DiceNotifier extends ChangeNotifier {
List<int> dices = [];
void addDice() {
dices.add(dices.length);
notifyListeners();
}
void removeDice(int id) {
dices.remove(id);
print(id);
notifyListeners();
}
}
final diceProvider = ChangeNotifierProvider((_) {
return DiceNotifier();
});
class MyHomePage extends ConsumerWidget {
#override
Widget build(BuildContext context, ScopedReader watch) {
final dices = watch(diceProvider).dices;
return Scaffold(
appBar: AppBar(
title: Text("Dice"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
...dices.map((d) => DiceWidget(value: d)).toList(),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
context.read(diceProvider).addDice();
},
child: Icon(Icons.add),
),
);
}
}
dice_widget.dart:
class DiceWidget extends StatefulWidget {
#override
_DiceWidgetState createState() => _DiceWidgetState();
}
class _DiceWidgetState extends State<DiceWidget> {
#override
Widget build(BuildContext context) {
return FlatButton(
child: Text(
widget.value.toString() ?? '',
),
onLongPress: () {
final dice = context.read(diceProvider);
dice.removeDice(widget.value);
print(widget.value);
},
);
}
}

How Can I Update Image after few seconds in flutter?

I'm Building An Flutter Application which requires image changes after a period of time. I thought using while loop with a sleep method inside may solve the problem. But It didn't, Image is only getting change after the loop ends. Application UI also gets froze.
Desired Output: Image should be changed after every 10 seconds.
Image and Button text is not Updating When Loop is running, please help me to get the desired output.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: Test(
),
),
)
);
}}
class Test extends StatefulWidget {
#override
_TestState createState() => _TestState();
}
class _TestState extends State<Test> {
int imgnumber=1;
int varToCheckButtonPress = 0;
String BtnTxt = "START";
void inc(){
while(imgnumber<10)
{
print(imgnumber);
setState(() {
sleep(Duration(seconds:5));
imgnumber++;
});
}
}
#override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Expanded(flex: 1,
child: Container(
child: Image.asset('images/'+imgnumber.toString()+'.png'),
height: 500,
width:500,
color: Colors.green,
),
),
FlatButton(
child: Text(BtnTxt),
onPressed: (){
if (varToCheckButtonPress == 0) {
setState(() {
BtnTxt = 'PAUSE';
varToCheckButtonPress = 1;
});
} else if (varToCheckButtonPress == 1) {
setState(() {
BtnTxt = 'RESUME';
varToCheckButtonPress = 0;
});
}
inc();
},
)
],
);
}
}
you shouldn't use sleep in the setState try replacing the inc function with this:
void inc() async {
while(imgnumber<10)
{
print(imgnumber);
await Future.delayed(const Duration(seconds: 10));
setState(() {
imgnumber++;
});
}
}

How to call method at App start if I am using provider?

I want to complete get request to server to get data for my app at it start. I read several topics that describe how to run method after building widgets. But all of them are describe situations when provider is not using. And I am not sure that it's good idea to do this request inside widget.
I tried several approaches but did not get success.
Here is my code:
void main() async {
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: ChangeNotifierProvider<TenderApiData>(
builder: (_) => TenderApiData(), child: HomePage()),
);
}
}
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(appBar: AppBar(), body: MainContainer());
}
}
class TenderApiData with ChangeNotifier {
String access_token;
List<Map<String, String>> id_names;
String access_token_url = "https://...";
getApiKey() async { // I need to call this method at app start up
var response = await http
.post(access_token_url, headers: {"Accept": "application/json"});
if (response.statusCode == 200) {
access_token = json.decode(response.body)['access_token'];
notifyListeners();
}
}
}
class MyTestWidget extends StatefulWidget {
MyTestWidgetState createState() => MyTestWidgetState();
}
class MyTestWidgetState extends State<MyTestWidget> {
bool isKeyGetted = false;
// before I used this when I extracted data on click event.
// I am not sure that it's needed now
#override
void didChangeDependencies() {
if (!isKeyGetted) {
Provider.of<TenderApiData>(context).getApiKey();
isKeyGetted = !isKeyGetted;
}
super.didChangeDependencies();
}
#override
Widget build(BuildContext context) {
if (!isKeyGetted) {
Provider.of<TenderApiData>(context).getApiKey();
isKeyGetted = !isKeyGetted;
}
var result = Provider.of<TenderApiData>(context).access_token;
var test = Provider.of<TenderApiData>(context).id_names;
return Column(
children: <Widget>[
RaisedButton(
onPressed: Provider.of<TenderApiData>(context).getRegionsList,
child: Text("get regions"),
),
],
);
}
}
class MainContainer extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Table(
children: [
TableRow(children: [
Row(
children: <Widget>[
Container(child: MyTestWidget()),
Container(child: Text("Regions"),),
Expanded(child: SelectRegions(), )
],
)
]),
TableRow(children: [
Row(
children: <Widget>[
Text("Label"),
Text("Value"),
],
)
]),
],
);
}
}
You can store TenderApiData as member of MyApp, make a startup call in MyApp constructor and pass existing instance to descendants.
Here is how it will look:
class MyApp extends StatelessWidget {
final TenderApiData _tenderApiData = TenderApiData();
MyApp() {
_tenderApiData.getApiKey();
};
#override
Widget build(BuildContext context) {
return MaterialApp(
home: ChangeNotifierProvider<TenderApiData>(
builder: (_) => _tenderApiData, child: HomePage()),
);
}
}
Other classes will stay unchanged.
Another option would be to pass TenderApiData as constructor parameter into MyApp, making it more testable.
void main() {
final TenderApiData tenderApiData = TenderApiData();
tenderApiData.getApiKey(); // call it here or in MyApp constructor - now it can be mocked and tested
runApp(MyApp(tenderApiData));
}
class MyApp extends StatelessWidget {
final TenderApiData _tenderApiData;
MyApp(this._tenderApiData);
// ...
You can add a constructor on your TenderApiData do trigger custom logic:
class TenderApiData with ChangeNotifier {
TenderApiData() {
// TODO: call `getApiKey`
}
}
You can use FutureProvider value.
Separate method api to service (my_service.dart):
class MyService {
Future<String> getApiKey() async {
// I need to call this method at app start up
var response = await http
.post(access_token_url, headers: {"Accept": "application/json"});
if (response.statusCode == 200) {
return json.decode(response.body)['access_token'];
}
}
}
And than call from MyApp
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return FutureProvider<String>.value(
value: MyService().getApiKey(),
child: HomePage(),
);
}
}
In HomePage:
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
String token = Provider.of<String>(context);
return Scaffold();
}
}
You could also just use a boolean flag to run the method only once.
Provider
import 'screen.abstract.dart';
class MyProvider with ChangeNotifier {
_hasInitialized = false;
// This will only be run once, when called
fetchApiOnce() {
if (_hasInitialized) {
return;
}
_hasInitialized = true;
/* DO STUFF */
}
}

Navigating from a plugin callback

The problem is when I want to navigate from a callback - which is invoked by plugin - new page is pushed in as a widget inside my page.
This is the code:
import 'dart:async';
import 'package:barcode_scan/barcode_scan.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() {
runApp(new MaterialApp(
home: new MyApp(),
) );
}
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => new _MyAppState();
}
class _MyAppState extends State<MyApp> {
String barcode = "";
#override
initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Barcode Scanner Example'),
),
body: new Center(
child: new Column(
children: <Widget>[
new Container(
child: new MaterialButton(
onPressed: scan, child: new Text("Scan")),
padding: const EdgeInsets.all(8.0),
),
],
),
));
}
Future scan() async {
try {
String barcode = await BarcodeScanner.scan();
print("${context}");
Navigator.push(context, MaterialPageRoute(
builder: (context) {
return new BarcodePage(barcode);}
));
setState(() => this.barcode = barcode);
} on PlatformException catch (e) {
if (e.code == BarcodeScanner.CameraAccessDenied) {
setState(() {
this.barcode = 'The user did not grant the camera permission!';
});
} else {
setState(() => this.barcode = 'Unknown error: $e');
}
} on FormatException{
setState(() => this.barcode = 'null (User returned using the "back"-button before scanning anything. Result)');
} catch (e) {
setState(() => this.barcode = 'Unknown error: $e');
}
}
}
class BarcodePage extends StatefulWidget {
BarcodePage(String s) {
str = s;
}
String str;
#override
State<StatefulWidget> createState() {
return _BarcodePageState(str);
}
}
class _BarcodePageState extends State<BarcodePage> {
String str;
_BarcodePageState(String s ){
str = s;
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(title: new Text("Bar code"),),
body: new Text(str),
);
}
}
You can find the application in https://github.com/arashbi/flutter_barcode_reader example folder
This is related to my question before, but simpler setup.
AFAI understand the problem is that callback is happening in the middle of render pipeline, and it causes the wrong behaviour. The solution is to use either Future.delayed or SchedulerBinding.instance.addPostFrameCallback
These methods causes the navigation to happen after the render pipeline, and the navigator can do its job properly