Flutter call RFlutter Alert from another class - flutter

I using flutter alert package rflutter_alert 1.1.0 , is it fine when writing the same code on same page. However due to many function making my code is too lengthy on 1 page.
So I try to split the alert function to another dart file, but I get the error of
A value of type 'Future<bool>' can't be returned from method 'build' because it has a return type of 'Widget'.dart(return_of_invalid_type)
if I write like this
dialog dart
import 'package:flutter/material.dart';
import 'package:rflutter_alert/rflutter_alert.dart';
class Dialog extends StatefulWidget {
#override
_DialogState createState() => _DialogState();
}
class _DialogState extends State<Dialog> {
#override
Widget build(BuildContext context) {
return Alert(
context: context,
type: AlertType.error,
title: "RFLUTTER ALERT",
desc: "Flutter testing Testing testing.",
buttons: [
DialogButton(
child: Text(
"COOL",
style: TextStyle(color: Colors.white, fontSize: 20),
),
onPressed: () => Navigator.pop(context),
width: 120,
)
],
).show();
}
}
What is correct way to split out the rFlutter alert code and call it when press the button ?

build need a Widget no ant Alert , in order to call the alert but the code inside click callback (Button for example).
#override
Widget build(BuildContext context) {
return Container(
child: FlatButton(onPressed: (){
Alert(
context: context,
type: AlertType.error,
title: "RFLUTTER ALERT",
desc: "Flutter testing Testing testing.",
buttons: [
DialogButton(
child: Text(
"COOL",
style: TextStyle(color: Colors.white, fontSize: 20),
),
onPressed: () => Navigator.pop(context),
width: 120,
)
],
).show();
}, child: Text("CLICK ME!!")),
);
}

Related

Stack with global z-index?

I have a DataTable in which some cells have links. Ideally, I would like to fetch a preview about the link's content whenever hovering over the link, which I was able to achieve using the Stack widget. However, since the stacked preview is inside the DataCell, it seems like I'm not able to raise its "z-index" to be on top of the rest of the table.
Is this not possible with Flutter, or is there a way around it?
The only way I imagine this working, without something to update a global z-index, would be for the cell to update a global state and then have the thumbnail preview appear on a Stack above the DataTable level. But I wish there was a less clunkier way to do it...
3 widgets I've tried but to no avail — they might work, I don't know —:
Tooltip
Overlay
FloatingActionButton
My whole app is here, and the precise commit is 0303732. The relevant code is this ClickableLink widget:
import 'package:flutter/material.dart';
import 'package:flutter/gestures.dart';
import 'package:url_launcher/url_launcher.dart';
import '../schema/links.dart';
#immutable
class ClickableLink extends StatefulWidget {
const ClickableLink({
Key? key,
required this.link,
this.linkText,
this.color = Colors.blue,
}) : super(key: key);
final Link link;
final String? linkText;
final Color color;
#override
State<ClickableLink> createState() => _ClickableLinkState();
}
class _ClickableLinkState extends State<ClickableLink> {
Widget hoverWidget = const SizedBox.shrink();
void _fetchPreview(PointerEvent pointerEvent) {
setState(() {
if (widget.link.host == 'online-go.com' && widget.link.prePath == 'game') {
hoverWidget = Positioned(
top: 25,
child: Image.network('https://online-go.com/api/v1/games/${widget.link.id}/png'),
);
}
});
}
void _onExit(PointerEvent pointerEvent) {
setState(() {
hoverWidget = const SizedBox.shrink();
});
}
#override
Widget build(BuildContext context) {
return MouseRegion(
onHover: _fetchPreview,
onExit: _onExit,
child: Stack(
clipBehavior: Clip.none,
children: [
SelectableText.rich(
TextSpan(
text: widget.linkText ?? widget.link.id,
style: TextStyle(color: widget.color),
recognizer: TapGestureRecognizer()
..onTap = () async => launch(widget.link.completeLink),
),
),
hoverWidget,
],
),
);
}
}
The problem here is due to the fact that your Stack widget, defined inside ClickableLink, will be at a "lower" point (inside your app widget tree) than every other GameResultCell.
So even the higher z-index will still be behind the other GameResultCells.
To fix this I would reccomend changing your structure and define an higher point in your structure to show the preview.
Another way could be using a library to nest your preview inside a tooltip. Take a look at this one for example:
just_the_tooltip: ^0.0.11+2. With this package, you could even use a StatelessWidget.
The result here is more similar to what I suppose you were expecting.
class ClickableLink extends StatelessWidget {
#override
Widget build(BuildContext context) {
return JustTheTooltip(
content: Image.network(
'https://online-go.com/api/v1/games/${widget.link.id}/png',
),
child: SelectableText.rich(
TextSpan(
text: widget.linkText ?? widget.link.id,
style: TextStyle(
color: widget.color ??
(DogempTheme.currentThemeIsLight(context)
? const Color(0xff1158c7)
: Colors.orange.withOpacity(0.85)),
),
recognizer: TapGestureRecognizer()
..onTap = () async => launch(widget.link.completeLink),
),
),
);
}
}
Lastly you could use a Dialog, but the resulting behaviour is a bit different.
Take a look at this code if you want to try:
class _ClickableLinkState extends State<ClickableLink> {
Widget hoverWidget = const SizedBox.shrink();
void _fetchPreview(PointerEvent pointerEvent) {
showDialog(
context: context,
builder: (context) {
return Dialog(
backgroundColor: Colors.transparent,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Image.network(
'https://online-go.com/api/v1/games/${widget.link.id}/png'),
const SizedBox(
height: 16.0,
),
TextButton(
onPressed: () async => launch(widget.link.completeLink),
child: const Text('Go to complete link'))
],
),
);
},
);
}
#override
Widget build(BuildContext context) {
return MouseRegion(
onHover: _fetchPreview,
child: Stack(
clipBehavior: Clip.none,
children: [
SelectableText.rich(
TextSpan(
text: widget.linkText ?? widget.link.id,
style: TextStyle(
color: widget.color ??
(DogempTheme.currentThemeIsLight(context)
? const Color(0xff1158c7)
: Colors.orange.withOpacity(0.85)),
),
recognizer: TapGestureRecognizer()
..onTap = () async => launch(widget.link.completeLink),
),
),
],
),
);
}
}

The method 'navigate' isn't defined for the type 'FindDevicesScreen' - Flutter

I get this error: The method 'navigate' isn't defined for the type 'FindDevicesScreen'.
Try correcting the name to the name of an existing method, or defining a method named 'navigate'.
My code is:
class FindDevicesScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
bool scanResult = false;
bool connectedResult = false;
return Scaffold(
appBar: AppBar(
title: Text('Find Adam'),
actions: <Widget>[
NotificationScreen(
title: Text('cart_no_count',
style: Theme.of(context).textTheme.headline6),
content: Text(
'cart_is_currently_empty',
style: Theme.of(context).textTheme.bodyText2,
textAlign: TextAlign.center,
),
iconData: FeatherIcons.shoppingCart,
textButton: Text('cart_return_shop'),
styleBtn: ElevatedButton.styleFrom(padding: paddingHorizontalLarge),
onPressed: () => navigate(context, {
"type": "tab",
"router": "/",
"args": {"key": "screens_home"}
}),
)
],
),
....
The error is in onPressed: () => navigate(context, {
The "navigate" function is in another file that I import. I got that "NotificationScreen(" code snippet from another screen where it does work. Why doesn't it work here?
Here I am attaching a snippet of the code that does work on the other screen.:

Flutter dialog with MVC

I am trying to display a dialog box with MVC pattern.
I want the dialog box to be a widget. like so:
AlertDialog gameDecisionDialog({
required VoidCallback onClick,
required String strDecision,
required Color decisionColor,
required BuildContext context,
}) {
return AlertDialog(
titleTextStyle: const TextStyle(
fontWeight: FontWeight.bold,
color: Colors.black,
fontSize: 20,
),
actionsOverflowButtonSpacing: 20,
actions: [
ElevatedButton(
onPressed: () {
Navigator.of(context).pop();
return onClick();
},
child: const Icon(Icons.next_plan_outlined),
),
],
content: Text(strDecision),
);
}
This dialog will be called in the model layer. Depending what happens during the app, a dialog will appear. The issue, is the context portion.
does it make sense to pass context from the view layer down to controller layer and then to model layer? Seems inefficient.
Any ideas on how to do this? I am trying to avoid having the dialog box in the view layer, its going to get too messy.
---------------- UPDATE
modified my code to the below suggestion, BUT now my alert dialog doesn't show up.
See the following code (when button clicked do some stuff and then display dialog):
elevatedRectButton(
onClick: () {
setState(() {
MyController.stop();
gameDecisionDialog(
onClick: () {
MyController.start();
},
gameDecision: MyController.getGameDecision,
decisionColor: Colors.amber,
context: context,
);
});
},
mIcon: const Icon(Icons.do_not_touch),
subText: 'STOP',
minWidth: 20,
height: 20,
bgColor: Colors.red,
),
I fear that calling a widget within a widget might be causing this issue?
Passing a BuildContext into a model/controller would not be recommended. Try to call the alert from the widget after the work in the model has been done or when an error is thrown.
Example:
onPress: () async {
//Some trigger callback
startLoading();
await controller.doWork().catchError((e) {
stopLoading();
showAlert(context, 'Some Message etc');
});
stopLoading();
}

Undefined name 'task' isn't letting my app run

I am having a problem running my app. I am trying to create a todolist app but I am new to coding so I am battling. I am not sure where the problem is. I a using Android Studio I have two files and I have put all the code in here except the import and run code. I have tried fixing all the errors but they just seem to cause more. I cannot run my app. (I have removed brackets in places as there is too much code when posting this question) Please can you help me out.
main.dart:
import 'package:flutter/material.dart';
import 'Task_Card.dart';
void main() {
runApp(MaterialApp(
home: TaskList(),
));
}
class TaskList extends StatefulWidget {
#override
_TaskListState createState() => _TaskListState();
}
class _TaskListState extends State<TaskList> {
final task = Task('Grocery');
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[800],
appBar: AppBar(
title: Text('ToDoList'),
centerTitle: true,
backgroundColor: Colors.grey[900],
),
body: SingleChildScrollView(
child: Column(),
),
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.black,
onPressed: () {
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => TaskCard(
task: task,
done: () {}
,)
),
);},
child: Icon(
Icons.add
),
),
);
}
}
class Task {
late String task;
Task(this.task);
}
Task_Card.dart:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class Task {
String task;
Task(this.task);
}
class TaskCard extends StatelessWidget {
final Task task;
final Function() done;
TaskCard({required this.task, required this.done});
#override
Widget build(BuildContext context) {
return Card(
margin: EdgeInsets.fromLTRB(16.0, 16.0, 16.0, 0.0),
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
task.task,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 18.0,
color: Colors.grey[900],
),
),
SizedBox(height: 6.0,),
TextButton.icon(
onPressed: done,
label: Text(
'Delete Quote',
),
style: TextButton.styleFrom(
primary: Colors.black,
),
icon: Icon(
Icons.delete,
color: Colors.black,
),
),
],
),
),
);
}
}
Here is the error:
I hope you have a task model in your project. If it's not there create one (Just adding an example model, you need to create one based on your own requirement):
class Task {
String task;
Task(this.task);
}
In your TaskListState create an instance of this model:
class _TaskListState extends State<TaskList> {
final task = Task('Grocery');
// Remaining code
}
Note: The above code will always show Grocery, in your actual app you may need to dynamically create the task object with actual value.
please try this:
...
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) =>
TaskCard(task: widget.task, done: () {})
...
instead of
...
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) =>
TaskCard(task: task, done: () {})
...
Try this
Undefined 'task' usually means that the item referenced has no definition. Did you remember to create a separate Task class (in a data file) and import that file into the file throwing the error?
You'll also need to initialize the task data somewhere before using it.
I do not see where you pass the initialized task into your argument defined in your widget. You might want to override initState in the state widget to initialize the Task so that it is not null or pass a new task to the widget when you call it on your Navigator.
Finally in the State Content class you will want to refer to the task as widget.task because the final variable is only accessible by reference through widget.task.
To be clear:
You are currently doing this:
MaterialPageRoute(builder: (context) => TaskCard(
task: task,
done: () {}
,)
The problem is that you never initialized the task object. Even this might work (its hard to say since I don't see. the Task.dart file at this point).
MaterialPageRoute(builder: (context) => TaskCard(
task: Task(),
done: () {}
,)
Even better before you return Scaffold you could create a new task object and evaluate the data from inside the done completion handler.
Task mytask = Task();
...
return Scaffold
and then send that initialized task into the widget while evaluating any properties on the done completion handler.
MaterialPageRoute(builder: (context) => TaskCard(
task: mytask,
done: () {
print(mytask.prop1);
}
,)

Flutter - call Navigator inside switch which it is inside builder

I want to navigate to QrScan screen once the icons get pressed, instead, I got an error!!
setState() or markNeedsBuild() called during build
I want to navigate to that screen and get data from QR Codes, after that I want this data to be shown on another screen!
It says:
This Overlay widget cannot be marked as needing to build because the framework is already in the process of building widgets.
A widget can be marked as needing to be built during the build phase only if one of its ancestors is currently building.
This exception is allowed because the framework builds parent widgets before children, which means a dirty descendant will always be built.
Otherwise, the framework might not visit this widget during this build phase.
The widget on which setState() or markNeedsBuild() was called was:
Overlay- [LabeledGlobalKey#a5a46]
The widget which was currently being built when the offending call wasmade was: builder
class MainTabsScreen extends StatefulWidget {
#override
_MainTabsScreenState createState() => _MainTabsScreenState();
}
class _MainTabsScreenState extends State<MainTabsScreen> {
int page = 3;
void _openScanner() {
Navigator.push(context, MaterialPageRoute(builder: (context) => QrScan()));
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Builder(
builder: (context) {
switch (page) {
case 0:
return ExploreScreen();
case 1:
return OffersScreen();
case 2:
_openScanner();
break;
case 3:
return AltersScreen();
case 4:
return ChatsScreen();
default:
return ExploreScreen();
}
},
),
),
bottomNavigationBar: ConvexAppBar(
top: -20.0,
backgroundColor: Colors.white,
activeColor: Color(0xBB0BCC83),
color: Color(0xBB0BCC83),
height: 53.0,
elevation: 0.0,
initialActiveIndex: 3,
items: [
TabItem(
icon: Icons.home,
title: 'Home',
),
TabItem(
icon: Icons.list,
title: 'Offers',
),
TabItem(
icon: Icons.qr_code,
title: 'Scan',
),
TabItem(
icon: Icons.add_alert,
title: 'Notification',
),
TabItem(
icon: Icons.chat,
title: 'Chats',
),
],
onTap: (id) {
setState(() => page = id);
},
),
);
}
}
As discussed in comments, a solution was to call the navigator.push when id == 2 within the onTap function.