How to make a save changes button? - flutter

I have an AlertDialog that I use as a settings window, when the user opens it, the Apply button is not active, I would like that when the settings change, the button becomes active and saves the changes. How can I do this?
showAlertDialogSettings(BuildContext context, state) {
Widget okButton = TextButton(
child: Text("Apply"),
onPressed: null,
);
Widget cancelButton = TextButton(
child: Text("Close"),
onPressed:() => Navigator.pop(context),
);
AlertDialog alert = AlertDialog(
title: Center(child: Text("Settings")),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Sound:'),
SwitchWidget(),
],),
SizedBox(
height: 48,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Difficulty:'),
Padding(
padding: const EdgeInsets.only(right: 5),
child: DropDownButtonSettingsWidget()
),
],),
),
],
),
actions: [
okButton,
cancelButton,
],
);
showDialog(
context: context,
builder: (BuildContext context) {
return BackdropFilter (
filter: ImageFilter.blur(sigmaX: 6, sigmaY: 6),
child: alert );
},
);
}

You will need to maintain state of both the sound and the difficulty values (there are many ways to tackle this), though the simplest would be to split out the "body" of the AlertDialog to be a StatefulWidget to contain its state. From there, you can check whether values have changed and update the view state to enable the apply button.
It's highly recommended to not mix business logic with UI logic, so this widget shouldn't actually do any of the saving. Inputs can be encapsulated within a class, and then this class can be passed back via Navigator.of(context).pop(T) (where T is your value class, see docs) upon closing the dialog from the apply button callback.
// Input passed back via `pop(T)` can be retrieved via:
final input = await showDialog(MyAlertDialog());

Related

AppCenter.checkForUpdateAsync() method always returns null

In my mobile app I use the AppCenter.checkForUpdateAsync() (flutter_appcenter_bundle package) method to check for updates and prompt the user to update the application if needed. However, the method always returns null, even if the current version is not the latest.
I tried to change the versions of the package, and in accordance with the documentation, I published applications with forced updates enabled. But it didn't help.
I have no more ideas what can be done.
The method checkForUpdateAsync is called when the button is clicked.
Details:
Future<void> checkAppUpdate() async {
final result = await AppCenter.checkForUpdateAsync(); // always returns null
logger.i(LogMessage('result $result', name: 'checkAppUpdate'));
if (result == null) {
showDialog(
context: context,
builder: (BuildContext context) => AlertDialog(
content: Column(
mainAxisSize: MainAxisSize.min,
children : <Widget>[
Container(
child: Text(
"Текущая версия приложения актуальна",
textAlign: TextAlign.center,
style: TextStyle(height: 1.44)
),
),
SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
child: Text('Ок'),
onPressed: () => Navigator.of(context).pop()),
])
],
),
)
);
}
}
Flutter version 1.12.13+hotfix.6
flutter_appcenter_bundle: 3.1.1+1

How can i create a conditional dialog that's not dismissible in the dashboard of my flutter app

I have a view, dashboard.dart, and in this file i have conditional views in which i created a different file for the individual views i'm rendering.
How do i render a conditional dialog that fills the whole screen instead of a widget?
I tried creating a widget that uses showGeneralDialog and then pass the widget to my dashboard.dart file but it seem i don't know how to go about it.
I need ideas or help
I have a snippet of my dashboard.dart file which at the end checks if the user is subscribed or not:
Widget content(context) {
return Obx(() => Column(
children: [
Expanded(
child: ListView(
padding: const EdgeInsets.only(
top: 40, left: 20, right: 20, bottom: 20),
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
AppLocalizations.of(context)!.welcome +
" ${user.firstName}",
style: const TextStyle(fontSize: 20)),
if (user.userType == "player")
InkWell(
onTap: () {
CustomSnackBar().show(
'${user.profileViews ?? "0"} profile views');
},
child: InkWell(
onTap: () {
playersController.fetchPlayerInfo(
context, user.id);
TabRouting()
.pushScreen(context, const PlayerInfo());
},
child: CircleAvatar(
backgroundImage: NetworkImage(
"${dotenv.env['BACKEND_URL']}${user.photo?.replaceAll("public", "storage")}"),
),
),
)
],
),
///SHOW SUBSCRIPTION STATUS
if (servicesController.subscription.isEmpty &&
!servicesController.loading &&
user.userType != "club_official")
const SubscriptionNotice(),
And the widget i'm returning is SubcriptionNotice().
What i'm asking is how do i show a dialog if the user is not subscribed and pass it to that condition?
If i can use a widget, how do i configure this widget?
I tried using showGeneralDialog in my SubscriptionNotice widget but i can't seem to go about it.
You can use simple switch something like
showDialog ?? dialogWichYouWantToShow: OtherWidget
You eneter this screen and will see OtherWidget
When condition showDialog changes (use setState or something) it should display dialogWichYouWantToShow

How to create a form with add more field in flutter using flutter_form_builder?

Flutter Web
So I have a button called add tags which opens up a modal. The Modal has only one text field and two buttons called add another tag and submit.
Now what I want to do is when the user clicks the add another tag button the app will generate another text field.
I've already seen some videos and read the documentation but since I need to work on a modal and the modal has defined size I'm not sure how to handle issues like
What happens if the user adds a lot of tags. How can I make the modal scrollable?
I'm new to flutter_form_builder so I'm not sure if the modal can handle it or not.
Here's my code:
final _formKey = GlobalKey<FormBuilderState>();
Future buildAddTagsForm(BuildContext context,
{Function()? notifyParent}) async {
return await showDialog(
barrierDismissible: false,
barrierColor: Colors.black.withOpacity(0.5),
context: context,
builder: (context) {
var screen = MediaQuery.of(context).size;
return StatefulBuilder(
builder: (context, setState) {
return AlertDialog(
content: SingleChildScrollView(
child: Container(
height: screen.height / 2,
width: screen.height > 650 ? 600.00 : screen.height * 1,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: FormBuilder(
key: _formKey,
autovalidateMode: AutovalidateMode.onUserInteraction,
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
IconButton(
onPressed: () {
Navigator.pop(context);
},
icon: Icon(
Icons.cancel_presentation_rounded,
),
),
],
),
SizedBox(
height: 10,
),
FormBuilderTextField(
name: 'Tag Name',
decoration: InputDecoration(labelText: 'Tag name'),
validator: FormBuilderValidators.compose([
FormBuilderValidators.required(context),
]),
),
SizedBox(
height: 10,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
MaterialButton(
color: CustomColors.buttonColor,
child: Text(
"Add another tag",
style: TextStyle(
color: Colors.white,
),
),
onPressed: () {},
)
],
),
SizedBox(
height: 10,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
MaterialButton(
color: CustomColors.buttonColor,
child: Text(
"Submit",
style: TextStyle(
color: Colors.white,
),
),
onPressed: () {},
)
],
),
],
),
),
),
),
),
);
},
);
},
);
}
I'm assuming by "modal" we're talking about the AlertDialog here:
return AlertDialog(
content: SingleChildScrollView(
By using SingleChildScrollView as the AlertDialog content:, we can have any size / any number of text fields we like in the dialog. If their number are too many for the height of dialog inside our screen, the content will scroll.
Although, its immediate child Container with height prevents the SingleChildScrollView from doing its magic:
return AlertDialog(
content: SingleChildScrollView(
child: Container(
height: screen.height / 2,
I think the above AlertDialog would not scroll because it would never be big enough to need to scroll. Plus, any fields added that combine to be taller than that specified height (screen.height / 2) will cause an overflow warning and be cutoff visually.
So to answer question #1: "What happens if the user adds a lot of tags. How can I make the modal scrollable?"
using SingleChildScrollView is the right idea
lets swap the position of the Container with height and the SingleChildScrollView and this should allow the dialog to grow & scroll as needed as columns in FormBuilder increase
Your question #2: "I'm new to flutter_form_builder so I'm not sure if the modal can handle it or not."
flutter_form_builder shouldn't affect how SingleChildScrollView works
Example
Here's a partial example of an AlertDialog with scroll view content: that can grow in number.
Widget build(BuildContext context) {
return Container(
height: 300,
child: AlertDialog(
content: SingleChildScrollView(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: items,
),
),
),
actions: [
OutlinedButton(
child: Text('Add Row'),
onPressed: _incrementCounter
)
]
),
);
}
The complete example runnable in DartPard is here. (Add a 6 or 7 rows and then scroll the content.)
Warning
There's a gotcha with using the above AlertDialog inside a sized Container. That Container with height is not enough to constrain the AlertDialog size.
Your showDialog builder: (that pushes the AlertDialog into existence) must provide additional constraints in order for the sized Container to have constraints to size itself within. Without these constraints, the AlertDialog will grow until it matches the device viewport size. I believe this is a quirk with how showDialog is written, since I'm guessing it's a modal layer on top of the current stack of routes. (Someone can correct me if I'm wrong.) It's only constraint is the physical device, but nothing else. By wrapping builder:'s output with a constraining widget (such as Center) the output will be able to size itself.
To see this in action, remove the Center widget from the full example above an re-run it. The dialog will grow to fill the screen when adding rows instead of being at max 300px in height.
child: OutlinedButton(
child: Text('Open Dialog'),
onPressed: () => showDialog(
context: context,
builder: (context) => Center(child: MyDialog())
),
)

Dialog state does not change after restarting (closing and opening again) in flutter

I have defined one button inside one StatelessWidget (This will have the bloc creation logic and injecting using bloc provider, ), on click of the button i am showing a dialog and passing the bloc instance to it, as shown in the code.
//EsignBloc is defined here in parent statelessWidget. Defined i.e. creating the bloc instance and passing through the BlocProvider. Removed the code for simplicity
//This listener will be called when Button defined inside statelessWidget will be clicked. this is responsible for showing the dialog.
void _onClickHere(
BuildContext context,
) {
final dialog = Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppConstants.borderRadius),
),
elevation: 0.0,
backgroundColor: Colors.transparent,
child: _GetSignUsingOtpView(),
);
showDialog(
context: context,
builder: (_) => BlocProvider<EsignBloc>(
create: (_) => BlocProvider.of<EsignBloc>(context), // passing already created bloc to dialog
child: WillPopScope(
onWillPop: () => Future.value(false),
child: dialog,
),
),
barrierDismissible: false,
);
}
Pasting some code of _GetSignUsingOtpView()
class _GetSignUsingOtpView extends StatelessWidget {
#override
Widget build(BuildContext context) {
return BlocBuilder<EsignBloc, EsignState>(builder: (context, state) {
return Container(
decoration: BoxDecoration(
color: AppColor.white,
borderRadius: BorderRadius.circular(
AppConstants.borderRadius,
),
),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Align(
alignment: Alignment.centerRight,
child: InkWell(
onTap: () => _closeDialog(context),
child: Padding(
padding: const EdgeInsets.only(top: 8.0, right: 8),
child: Icon(
Icons.cancel,
color: AppColor.primaryDark,
size: SizeConfig.safeBlockVertical * 2,
),
),
),
),
Padding(
padding: const EdgeInsets.all(24),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
PrimaryText(text: state.otp), // data does not change after closing and opeing dialog again
PrimaryText(text: state.remainingTime), // data does not change after closing and opeing dialog again
],
),
),
],
),
);
});
}
void _closeDialog(BuildContext context) {
Navigator.pop(context);
}
}
The problem that I am facing is whenever the dialog opens again after closing, it doesn't show the latest data from the bloc. The dialog just shows whatever previous data is in the bloc. Can someone point it out, where i am making the mistake?
The reason that your dialog is not showing new data is because you are creating a new instance of the bloc. Even though you say that you're not.
BlocProvider<EsignBloc>(
create: (_) => BlocProvider.of<EsignBloc>(context), // passing already created bloc to dialog
child: ...
In some cases, BlocProvider can be used to provide an existing cubit to a new portion of the widget tree. This will be most commonly used when an existing cubit needs to be made available to a new route. In this case, BlocProvider will not automatically close the cubit since it did not create it.
To not create a new instance, you need to use BlocProvider.value. You can read more about it here
BlocProvider.value(
value: BlocProvider.of<EsignBloc>(context),
child: ...,
);
Instead of creating a new instance, this will use the previous instance and provide it to the child widget and will NOT close the bloc when its done using it. This is handy for dialogs and navigation.

Alert Dialogue Box inside column in Flutter

In my app users are required to submit their government ID's for verification to keep using the app. On the basis of the condition "isIDverified" it displays a text "Verified" or if it's under review it displays "Under Review". Inside the verified condition I want to put a popup which will say "Your account is under review" along with the text somewhere around this green empty block.
My code:
if (isIDVerified) {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Verified',
style: kAppBarTitleTextStyle.copyWith(color: primaryColor),
),
SizedBox(
width: _screenUtil.setWidth(10),
),
Icon(
Icons.verified_user,
size: kPreferredIconSize,
color: Colors.green,
),
],
);
} else if (isIDUnderReview) {
return
Text(
'ID Under Review',
style: kAppBarTitleTextStyle.copyWith(color: primaryColor),
);
As far as I understand your question, I would like to answer it.
For displaying popups, you can make use of AlertDialogs.
You can do something like this.
void informUser() {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: new Text("Under Review"),
content: Column(
children: [ LIST OF WIDGETS ]
),
actions: <Widget>[
new FlatButton(
child: new Text("Close"),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
You can put your widgets in the Column widget of AlertDialog's content.