How to call alertdialog from another file? using flutter - flutter

how do I call the alert dialog from another dart file, when the user clicks the button in addstudents.dart, I want to make the alert dialog in another file just in case it can be reused? In my addstudents.dart i have this Container, please see the code below, thanks.
addstudents.dart
Container(
padding: EdgeInsets.only(top: 10),
width: (globals.screenWidth * 0.48),
height: (globals.screenHeight * 0.10),
decoration:
BoxDecoration(borderRadius: BorderRadius.circular(10)),
child: RaisedButton(
shape: new RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(10.0),
),
onPressed: () {
// calling another file dart
},
color: Colors.green,
child: RichText(
text: TextSpan(
text: "Confirmed!",
style: TextStyle(
fontWeight: FontWeight.bold,
fontFamily: "Nunito",
color: Colors.white,
fontSize: globals.fontsize_19)),
),
),
),
this is my alertdialog.dart
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter',
home: Scaffold(
appBar: AppBar(
title: Text('Flutter'),
),
body: MyLayout()),
);
}
}
class MyLayout extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: RaisedButton(
child: Text('Show alert'),
onPressed: () {
showAlertDialog(context);
},
),
);
}
}
showAlertDialog(BuildContext context) {
Widget okButton = FlatButton(
child: Text("OK"),
onPressed: () {},
);
AlertDialog alert = AlertDialog(
title: Text("My title"),
content: Text("This is my message."),
actions: [
okButton,
],
);
showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
);
}

Dunno if this is the best practice but here's what I'm doing
class Alerts {
static showAlertDialog(BuildContext context) {
Widget okButton = FlatButton(
child: Text("OK"),
onPressed: () {},
);
AlertDialog alert = AlertDialog(
title: Text("My title"),
content: Text("This is my message."),
actions: [
okButton,
],
);
// show the dialog
showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
);
}
}
I call them using Alerts.showAlertDialog(context);

Related

The device's exit button does not exit the app in flutter

i added willpopscope with back function In this project i added the exit code, but the app didn't end; instead it went to the homepage and I made this initial screen to start the project with all the details running in the homepage screen.
I want to exit from device but its not working Can somebody tell me what the problem is?
#override
Widget build(BuildContext context) {
Future<bool> _back() {
return showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text("Do you want to exit this app?"),
actions: <Widget>[
TextButton(
child: const Text('ok',style: TextStyle(fontSize: 15,color: Colors.indigo),),
onPressed: () {
Navigator.of(context).pop(true);
},
),
TextButton(
child: const Text('no',style: TextStyle(fontSize: 15,color: Colors.indigo),),
onPressed: () {
Navigator.of(context).pop(false);
},
),
],
);
}
).then((value) => value ?? false);
}
return WillPopScope(
onWillPop: _back,
child: SafeArea(
child: MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Container(
child: Padding(
padding: const EdgeInsets.all(80.0),
child: Column(
children: <Widget>[
Container(
Row(
children: <Widget>[
SizedBox(
height: 80,
width: 150,
child: OutlinedButton(
style: OutlinedButton.styleFrom(
side: BorderSide(
width: 3.0, color: Colors.indigo.shade900),
backgroundColor: Colors.transparent,
shape: const StadiumBorder()),
child: Text(
"LETS START",
),
onPressed: () {
Navigator.of(context).push(MaterialPageRoute( builder: (context) => homepage(langname: '',))); },
),
),
],
),
],
),
)),
)),
),
);
}
}
You can do Like this:
var currentBackPressTime;
Future<bool> onWillPop() {
DateTime now = DateTime.now();
if (currentBackPressTime == null ||
now.difference(currentBackPressTime) > Duration(seconds: 2)) {
currentBackPressTime = now;
Fluttertoast.showToast(msg: "Press Again to Exit!");
return Future.value(false);
} else {
exit(0);
// SystemChannels.platform.invokeMethod('SystemNavigator.pop');
return Future.value(false);
}
}
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: onWillPop,
child: Scaffold(
--------------

I cannot add appBar

I am trying to do a log in app, after finishing with the design I faced a problem where I could not add the function of going back to the old page, I searched and found about the appBar but I could not apply it.
class Body extends StatelessWidget {
const Body({
Key key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return Background(
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
"LOGIN",
style: TextStyle(fontWeight: FontWeight.bold),
),
SizedBox(height: size.height * 0.03),
SizedBox(height: size.height * 0.03),
RoundedInputField(
hintText: "Your Email",
onChanged: (value) {},
),
RoundedPasswordField(
onChanged: (value) {},
),
RoundedButton(
text: "LOGIN",
press: () {},
),
SizedBox(height: size.height * 0.03),
AlreadyHaveAnAccountCheck(
press: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return SignUpScreen();
},
),
);
},
),
],
),
),
);
}
}
You must use Scaffold Widget for displaying the AppBar try below code hope its helpful to you In Scaffold widget you declare AppBar for Appbar refer ducumentation here :
class AppBarPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Your Title'),
),
body: Container(),
);
}
}
Your Screen look like this->
use Scaffold.
class MyHomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("MyHomePage"),
actions: [
TextButton(onPressed: (){
Navigator.of(context).pop();
}, child: Icon(Icons.arrow_back))
],
),
body:Body() ,
);
}
}
on onPressed event you can return to old page
appBar can be used inside Scaffold.
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('AppBar Demo'),
actions: <Widget>[
IconButton(
icon: const Icon(Icons.arrow_back),
tooltip: 'Show Snackbar',
onPressed: () {
Navigator.of(context).pop();
},
),
],
),
body: const Center(
child: Text(
'This is the home page',
style: TextStyle(fontSize: 24),
),
),
);
}

How to call flutter dialog from separate class?

I need to separate my dialog to separate widgets an call from anywhere on some button click. Now my code looks like:
import 'package:flutter/material.dart';
class PlacesListScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return _Map();
}
}
class _Map extends StatefulWidget {
#override
_MapState createState() => _MapState();
}
class _MapState extends State<_Map> {
final _titleController = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('App name'),
actions: <Widget>[
IconButton(
icon: Icon(Icons.add),
onPressed: () {
return showDialog(
context: context,
builder: (ctx) => AlertDialog(
title: Text(
"Dialog title",
textAlign: TextAlign.center,
),
content: TextField(
decoration: InputDecoration(labelText: 'Title'),
controller: _titleController,
),
actions: <Widget>[
FlatButton(
onPressed: () {
Navigator.of(ctx).pop();
},
child: Text("No"),
),
FlatButton(
onPressed: () {
return showDialog(
context: context,
builder: (ctx) => StatefulBuilder(builder:
(BuildContext context, StateSetter setState) {
return AlertDialog(
title: Text(
"Second subdialog title",
textAlign: TextAlign.center,
),
content: Container(
width: 150,
height: 200,
decoration: BoxDecoration(
border:
Border.all(width: 1, color: Colors.grey),
),
child: Text('Here will be file'),
alignment: Alignment.center,
),
actions: <Widget>[
FlatButton(
onPressed: () {
Navigator.of(ctx).pop();
},
child: Text("No"),
),
FlatButton(
onPressed: () => Text('Here I will work with state'),
child: Text("Yes"),
),
],
);
}),
);
},
child: Text("Yes"),
),
],
),
);
},
),
],
),
body: Text('App body here'),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
floatingActionButton: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
FloatingActionButton(
onPressed: () => Text('Here will be called dialog function'),
child: Icon(Icons.add, color: Colors.white),
backgroundColor: Colors.green,
heroTag: 'mapZoomIn',
),
],
),
);
}
}
Now how I can this part of code (calling dialog) separate to another widget and call then using created widget.
showDialog(
context: context,
builder: (ctx) => StatefulBuilder(builder:
(BuildContext context, StateSetter setState) {
return AlertDialog(
title: Text(
"Second subdialog title",
textAlign: TextAlign.center,
),
content: Container(
width: 150,
height: 200,
decoration: BoxDecoration(
border:
Border.all(width: 1, color: Colors.grey),
),
child: Text('Here will be file'),
alignment: Alignment.center,
),
actions: <Widget>[
FlatButton(
onPressed: () {
Navigator.of(ctx).pop();
},
child: Text("No"),
),
FlatButton(
onPressed: () => Text('Here I will work with state'),
child: Text("Yes"),
),
],
);
}),
);
Firstly, you can refactor your StatefulBuilder(builder: (BuildContext context, StateSetter setState) { return AlertDialog(... into one separate widget like MyFancyDialog extends StatefulWidget. Then just call showDialog(..., MyFancyWidget()) when you need it.
Secondly, if you do not want the first method, you can extract the whole showDialog(...) into a function like void showMyFancyDialog() { showDialog... }. Is it also OK, since in dart functions are first class.
Did you try to create a new Stateful widget class at the bottom of your code and try to call that widget? If you didn't try that,
Go to under of your code and create a new Stateful class. (Let's say that myDialog)
Add the code that you want to call, inside of your "myDialog" widget
Go for where you want to call that code and try to call that class.
Hope this works for you.
Create a separate file. Import material package.
then create "Widget myDialog(context){ // paste your showDialog code here }"
Now your myDialog widget has been ready for using anywhere on whole project just import and call it.
When you call it pass BuildContext in its argument.
Its work for me.

A dialog has a delay to open, I get an error when navigating to another view before the dialog is generated. How can I make it not be generated?

I am new to flutter.
In my real problem, my client is in places where it is very frequent that the internet is very slow, so sometimes an attempt is made to make a web request and this may take time, so the user leaves the screen before the web request is completed. Sometimes my app after completing a web request generates a dialog. So here is where my problem lies, the user is trying to make a web request and while it is done, they leave the screen and then the dialog is generated.
I am trying to simulate this problem with a delay that later generates the dialog.
I am not thinking of any strategy to end the web request, what I want is to find a way that once I leave the screen, causes the dialog not to be generated something like a dispose
I made an example where I have 2 screens. On the second screen a dialog is generated with a delay of 5 seconds when the button is clicked. If I navigate to another screen before the dialog is opened I get an error. I assume this occurs because the view was destroyed and therefore the dialog cannot be opened.
What can I do to avoid the error when the dialog is generated after being in another view? if I am in another view I DO NOT WANT the dialog to be generated.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
print("main");
return MaterialApp(title: 'Provider Example', initialRoute: '/', routes: {
'/': (context) => Home(),
'home': (context) => Home(),
'dialogpage': (context) => Dialogpage(),
});
}
}
class Home extends StatelessWidget {
Home() {
print("home");
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
title: const Text('home'),
actions: <Widget>[
IconButton(
icon: const Icon(Icons.add_alert),
tooltip: 'Show Snackbar',
onPressed: () {
Navigator.pushNamed(context, "dialogpage");
},
),
],
),
body: const Center(
child: Text(
'home',
style: TextStyle(fontSize: 24),
),
),
);
}
}
class Dialogpage extends StatelessWidget {
Dialogpage() {
print("dialogpage");
}
dialog(BuildContext context) {
Future.delayed(const Duration(seconds: 5), () {
showDialog(
context: context,
barrierDismissible: false,
builder: (context) {
return AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.0)),
title: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(19.0),
topRight: Radius.circular(19.0),
),
),
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 5),
child: Text(
'Error',
style: TextStyle(color: Colors.white),
),
),
content: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
margin: EdgeInsets.only(top: 20.0, bottom: 20.0),
child: Icon(
Icons.error,
size: 50,
),
),
Text("dialog"),
],
),
titlePadding: EdgeInsets.all(0),
actions: <Widget>[
FlatButton(
child: Text('Aceptar'),
onPressed: () {
return Navigator.of(context).pop();
}),
],
);
});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('dialog'),
),
body: Center(
child: RaisedButton(
child: Text("show dialog"),
onPressed: () {
dialog(context);
}),
),
);
}
}
use Globalkey in scaffold in then check the context in dialog method is it != null
then run dialog otherwise don't...
GlobalKey _scafolldKey = GlobalKey<ScaffoldState>();
#override
Widget build(BuildContext context) {
return Scaffold(
key: _scafolldKey,
appBar: AppBar(
title: const Text('dialog'),),
body: Center(
child: RaisedButton(
child: Text("show dialog"),
onPressed: () {
dialog(context);
}),
),
);
}
}
dialog(BuildContext context) {
Future.delayed(const Duration(seconds: 2), () {
if(_scafolldKey.currentContext !=null){
showDialog();
}
});
}
Instead of Future.delayed, you should use Timer, which can be cancelled in onDispose method.
Working solution:
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
print("main");
return MaterialApp(
title: 'Provider Example',
initialRoute: '/',
routes: {
'/': (context) => Home(),
'home': (context) => Home(),
'dialogpage': (context) => Dialogpage(),
},
);
}
}
class Home extends StatelessWidget {
Home() {
print("home");
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('home'),
actions: <Widget>[
IconButton(
icon: const Icon(Icons.add_alert),
tooltip: 'Show Snackbar',
onPressed: () {
Navigator.pushNamed(context, "dialogpage");
},
),
],
),
body: const Center(
child: Text(
'home',
style: TextStyle(fontSize: 24),
),
),
);
}
}
class Dialogpage extends StatefulWidget {
#override
_DialogpageState createState() => _DialogpageState();
}
class _DialogpageState extends State<Dialogpage> {
Timer _timer;
#override
void dispose() {
_timer?.cancel();
super.dispose();
}
dialog(BuildContext context) {
_timer = Timer(
const Duration(seconds: 3),
() {
showDialog(
context: context,
barrierDismissible: false,
builder: (context) {
return AlertDialog(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20.0)),
title: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(19.0),
topRight: Radius.circular(19.0),
),
),
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 5),
child: Text(
'Error',
style: TextStyle(color: Colors.white),
),
),
content: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
margin: EdgeInsets.only(top: 20.0, bottom: 20.0),
child: Icon(
Icons.error,
size: 50,
),
),
Text("dialog"),
],
),
titlePadding: EdgeInsets.all(0),
actions: <Widget>[
FlatButton(
child: Text('Aceptar'),
onPressed: () {
return Navigator.of(context).pop();
},
),
],
);
},
);
},
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('dialog'),
),
body: Center(
child: RaisedButton(
child: Text("show dialog"),
onPressed: () {
dialog(context);
},
),
),
);
}
}
Try this code
class Dialogpage extends StatelessWidget {
...
Timer t;
dialog(BuildContext context) {
t = Timer(Duration(seconds: 5), () {
showDialog(...);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('dialog'),
leading: IconButton(
icon: Icon(Icons.arrow_back, color: Colors.black),
onPressed: () {
t?.cancel();
Navigator.of(context).pop();
},
),
),
body: Center(
child: RaisedButton(
child: Text("show dialog"),
onPressed: () {
dialog(context);
}),
),
);
}
}
Hope it helps.

Scaffold Drawer to showModalBottomSheet

At the homescreen of myApp() I have a stateless widget, it contains a MaterialApp and a Scaffold. Scaffold have a property of drawer and I passed I created a drawer, and one of the item in my drawer needs to open the showModalBottomSheet while closing the drawer. How can I achieve this? I've tried passing the context itself, and as globalKey.currentContext (after GlobalKey<ScaffoldState> globalKey = GlobalKey();) but the drawer sometimes closes, other time gives me a NoMethodFoundException (or something like that)
In short, how to have a Scaffold drawer that have one of the item, when tapped closes the drawer and showModalBottomSheet?
Current code:
class Timeline extends StatelessWidget {
#override
Widget build(BuildContext context) {
GlobalKey<ScaffoldState> homeScaffoldKey = GlobalKey();
return MaterialApp(
title: "Test",
theme: ThemeData(
appBarTheme: AppBarTheme(iconTheme: IconThemeData(color: Colors.black)),
),
home: Scaffold(
key: homeScaffoldKey,
drawer: showDrawer(homeScaffoldKey.currentContext),
backgroundColor: Colors.grey[100],
body: Stack(
children: <Widget>[
HomePageView(),
AppBar(
elevation: 0,
backgroundColor: Colors.transparent,
),
],
),
),
);
}
}
Drawer showDrawer(BuildContext context) {
void showCalendarsModalBottom() {
showModalBottomSheet(
context: context,
builder: (BuildContext builder) {
return ListView.builder(
itemCount: repo.calendars.length,
itemBuilder: (builder, index) {
return StatefulBuilder(
builder: (builder, StateSetter setState) => ListTile(
leading: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Checkbox(
value: repo.getIsEnabledCal(repo.getCal(index)),
onChanged: (value) {
setState(() {
repo.toggleCalendar(repo.getCal(index));
});
},
),
Container(
height: 14,
width: 14,
margin: EdgeInsets.only(left: 2, right: 6),
decoration: BoxDecoration(
color: Colors.redAccent,
shape: BoxShape.circle,
),
),
Text(
repo.getCal(index).name,
style: TextStyle(
fontSize: 16,
),
),
],
),
onTap: () {
setState(() {
repo.toggleCalendar(repo.getCal(index));
});
},
),
);
},
);
},
);
}
return Drawer(
child: ListView(
children: <Widget>[
DrawerHeader(
child: Align(
child: Text('Timeline', textScaleFactor: 2),
alignment: Alignment.bottomLeft,
),
),
ListTile(
title: Text('Dark Mode'),
onTap: () => Navigator.pop(context),
),
ListTile(
title: Text('Calenders'),
onTap: () {
Navigator.pop(context);
showCalendarsModalBottom();
},
)
],
),
);
}
Updated working code based on your code snippet:
You'll need to have statefulwidget that will help to pass the context from drawer to bottomsheet and pass the context as an argument in showCalendarModalBottomSheet() method.
void main() {
runApp(new MaterialApp(home: Timeline(), debugShowCheckedModeBanner: false));
}
class Timeline extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: "Test",
theme: ThemeData(
appBarTheme: AppBarTheme(iconTheme: IconThemeData(color: Colors.black)),
),
home: MyHomePage()
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
drawer: AppDrawer(),
backgroundColor: Colors.grey[100],
body: Stack(
children: <Widget>[
//HomePageView(),
AppBar(
elevation: 0,
backgroundColor: Colors.transparent,
)
],
)
);
}
Widget AppDrawer() {
return Drawer(
child: ListView(
children: <Widget>[
DrawerHeader(
child: Align(
child: Text('Timeline', textScaleFactor: 2),
alignment: Alignment.bottomLeft,
),
),
ListTile(
title: Text('Dark Mode'),
onTap: () => Navigator.pop(context),
),
ListTile(
title: Text('Calenders'),
onTap: () {
Navigator.of(context).pop();
showCalendarsModalBottom(context);
},
)
],
),
);
}
Future<Null> showCalendarsModalBottom(context) {
return showModalBottomSheet(context: context, builder: (context) => Container(
color: Colors.red,
// your code here
));
}
}
And the output is: When app drawer menu Calendar is tapped, it closes and opens the bottomsheet seamlessly. If you tap on app drawer again and repeat steps, you see smooth transition between drawer and bottomsheet. Hope this answers your question.