Flutter: Enable button when RatingBar value has been set - button

I am new to Flutter and am trying to figure out how to enable my action button only when a rating value has been selected in an AlertDialog. When the "submit" button has been selected with nothing selected, it still changes the value to e.g. 6.0 for some odd reason so an "if" statement may not work comparing it to null as I've tried it previously in the onPressed() method.
This is my method code to show the AlertDialog:
void _showDialog() {
showDialog(
context: context,
barrierDismissible: false,
builder: (context) {
return AlertDialog(
title: Text("Pain Rating"),
content: RatingBar(
onRatingChanged: (rating) {
setState(() {
_rating = rating;
print("rating changed: rating = $_rating");
});
},
maxRating: 10,
filledIcon: Icons.radio_button_checked,
emptyIcon: Icons.radio_button_unchecked,
isHalfAllowed: false,
filledColor: Colors.green,
emptyColor: Colors.green,
size: 28,
),
actions: <Widget>[
FlatButton(
child: const Text('SUBMIT'),
onPressed: () {
print("submit pressed: rating = $_rating");
Navigator.of(context).pop();
},
)
],
);
});
Currently when any or no rating has been selected and the "submit" button has been pressed it will close the dialog. I expect the "submit" button to be disabled until a rating has been selected

This is one suggested way to do it:
var _rating = 0.0
FlatButton(
child: const Text('SUBMIT'),
onPressed: _rating > 0.0
? () {
print("submit pressed: rating = $_rating");
Navigator.of(context).pop();
} : null,
)
If your _rating gets grater than 0, that means the used changed the value (assuming your rating can't be 0). If so, you enable the button by passing that VoidCallback... if not, the null value is called and that disables the button.
If by any reason you need the 0.0 value, then use a bool variable and change the value to true once you reach the onRatingChanged callback and then change my logic from _rating > 0.0 to simply your bool variable.

Related

How to send flutter search to Firebase Analytics event

Is there a way to catch only the final search to send in Firebase Analytics event?
_searchPressed() {
final FirebaseAnalytics analytics = FirebaseAnalytics.instance;
setState(() {
if (this._searchIcon.icon == Icons.search) {
this._searchIcon = new Icon(Icons.close);
this._appBarTitle = TextField(
decoration: new InputDecoration(
prefixIcon: new Icon(Icons.search),
),
onChanged: (text) {
text = text.toLowerCase();
setState(() {
_itemForDisplay = _item.where((item) {
var itemTitle = item.code.toLowerCase();
return itemTitle.contains(text);
}).toList();
if (text.length > 6) {
analytics.logEvent(
name: text.replaceAll(' ', ''),
parameters: {'term': text.replaceAll(' ', ''), 'vaule': 1});
//space not allowed in firebase
}
});
},
);
} else {
this._searchIcon = new Icon(Icons.search);
this._appBarTitle = new Text( 'Search bar' );
analytics.logEvent(
name: 'search_done',
parameters: {'term': "close", 'vaule': 1});
_itemForDisplay = _item;
}
});
}
A satisfactory solution is to capture the search when closing search is selected. The search is done simultaneously so there is no information when the search is completed. The only information about the end of the search is when you touch the close icon. Another option would be the longest search text.

Assistance required to get search query data render on screen. flutter/dart

I made this notes app which uses firestore to save data and it is working fine, no problem whatsoever.
Now I am trying to implement a search filter on notes and I can't find the right method to do it.
Here is my code that renders the notes on the screen
here is the reference image
List<Widget> _buildNotesView(
BuildContext context, NoteFilter filter, List<Note> notes) {
if (notes?.isNotEmpty != true) {
return [_buildBlankView(filter.noteState)];
}
final asGrid = filter.noteState == NoteState.deleted || notesView;
final factory = asGrid ? NotesGrid.create : NotesList.create;
final showPinned = filter.noteState == NoteState.unspecified;
if (!showPinned) {
return [
factory(notes: notes, onTap: _onNoteTap),
];
}
final partition = _partitionNotes(notes);
final hasPinned = partition.item1.isNotEmpty;
final hasUnpinned = partition.item2.isNotEmpty;
final _buildLabel = (String label, [double top = 26]) => SliverToBoxAdapter(
child: Container(
padding:
EdgeInsetsDirectional.only(start: 26, bottom: 25, top: top),
child: Text(
label,
style: TextStyle(
fontFamily: selectedFont,
color: kHintTextColorLight,
fontWeight: FontWeights.medium,
fontSize: 12,
),
),
),
);
//TODO
if (searchController.text.isNotEmpty) {
notes.forEach((note) {
if (note.title
.toLowerCase()
.contains(searchController.text.toLowerCase()) ||
note.content
.toLowerCase()
.contains(searchController.text.toLowerCase())) ;
//Do something here?
});
}
return [
if (hasPinned) _buildLabel('PINNED', 0),
if (hasPinned) factory(notes: partition.item1, onTap: _onNoteTap),
if (hasPinned && hasUnpinned) _buildLabel('OTHERS'),
factory(notes: partition.item2, onTap: _onNoteTap),
];
}
Any help would be great. I'm open to learning.

getx and weird problem: text won't change on UI

I am trying to create a search function from firebase
and i am using getx for the state management
I counter this weird problem, when I try to use the function directly it work, but when I use the firebase function it does not.
I will explain more on the code snipit.
this is my search textForm
TextFormField(
onChanged: (value) => database.searchForId(value),
decoration: InputDecoration(
focusColor: Colors.lightGreenAccent,
prefixIcon: Icon(
Icons.search,
color: Colors.lightGreenAccent,
),
labelText: 'Search...',
labelStyle: TextStyle(color: Colors.lightGreenAccent),
border: OutlineInputBorder(),
focusedBorder: OutlineInputBorder(
borderSide:
const BorderSide(color: Colors.lightGreenAccent),
),
)),
as you can see I am using on change value
database code for search
searchForId(searchText) {
FirebaseFirestore.instance
.collection('inventory')
.where('id', isGreaterThanOrEqualTo: searchText)
.get()
.then((snapshot) {
var data = snapshot.docs[0];
if (data['id'] != searchText) {
return;
} else {
searchController.changeId(data['id']);
searchController.changeName(data['name']);
searchController.changeQuantity(data['quantity']);
searchController.changeCost(data['cost']);
searchController.changeMyPrice(data['myPrice']);
}
});
}
and the controller
class SearchController extends GetxController {
var id = 'No info'.obs;
var name = 'No info'.obs;
var quantity = 'No info'.obs;
var cost = 'No info'.obs;
var myPrice = 'No info'.obs;
changeId(_id) {
id(_id);
print(id);
}
the print show me that the value is changed, but never update it on my UI
Obx(() => Text(searchController.id.value))
so i trid to call the controller dirctly (not using database file) and it work just fine, and UI updated
any idea why ?
the weird is the print show me the function get called and working fine ( i mean when i use database file as well ) but it never update the UI
I think u forgot to keep
SearchController searchcontroller = Get.put(SearchController());
if you initialized it before just find that controller using
SearchController searchcontroller = Get.find();
var id = 'No info'.obs;
searchController.changeId(data['id']);
changeId(_id) {
id(_id);
print(id);
}
In order to update your text in UI, you can either update your code
changeId(_id) {
id(_id);
print(id);
update(); // Calling update manually. update() is a function in GetxController to trigger the observable change.
}
or
changeId(String _id) {
id.value = _id;
}

Displaying video ads in a row with admob on flutter

Im interested if there is a way to display more than one RewardVideoAd in a row. Before opening one videoAd it must be loaded, so I tried to load another videoAd when other is opened, so that way when the videoAd is closed/rewarded/completed it shows the new one. But it isn't working here is the code I have tried.
(RewardedVideoAdEvent event, {String rewardType, int rewardAmount}) {
print("RewardedVideoAd event $event");
if (event == RewardedVideoAdEvent.opened) {
setState(() {
RewardedVideoAd.instance.load(
adUnitId: RewardedVideoAd.testAdUnitId,
targetingInfo: targetingInfo);
});
} else if (event == RewardedVideoAdEvent.closed ||
event == RewardedVideoAdEvent.completed ||
event == RewardedVideoAdEvent.rewarded ||
event == RewardedVideoAdEvent.failedToLoad) {
setState(() {
_coins += rewardAmount;
RewardedVideoAd.instance.show();
});
}
};
..and the buttons from where the first ad is started.
RaisedButton(
child: const Text('LOAD REWARDED VIDEO'),
onPressed: () {
RewardedVideoAd.instance.load(
adUnitId: RewardedVideoAd.testAdUnitId,
targetingInfo: targetingInfo);
},
),
RaisedButton(
child: const Text('SHOW REWARDED VIDEO'),
onPressed: () {
RewardedVideoAd.instance.show();
},
),
I wonder if there is a way to show 2 or 3 rewardVideoAds in a row, one after another. Thanks!

Flutter Enable/Disable Button based on TextFormField content

How can I activate/deactivate a button based on the content of a TextFormField?
I want to make sure a user can only press Button X if the TextFormField has 10 entered numbers (if it's a mobile number).
Thanks!
The state of the widget can be updated in the Form's onChanged callback which is called whenever any of the form fields' value changes. There you can use a form key to validate the form and set a flag to enable/disable the button. This solution allows you to scale to disable buttons in forms with multiple fields. For example,
/// Key used to reference the form.
final _formKey = GlobalKey<FormState>();
...
Form(
key: _formKey,
onChanged: () => setState(() => _enableBtn = _formKey.currentState.validate()),
child: ListView(
children: <Widget>[
TextFormField(
validator: (value) => value.length < 10 ?
'Number must be at least 10 digits' : // return an error message
null,
...
),
],
),
)
...
FlatButton(
onPressed: _enableBtn ?
() => _doSomething() :
null, // setting onPressed to null disables the button.
...
A simple way would be to set the autovalidate property of our TextFormField to true. This will automatically detect for changes on our TextFormField widget. We can then try to check if our TextFormField's value has a String length of 10 characters on the validator property . After that we can call setState to enable or disable our button (I use FlatButton in this example).
bool _btnEnabled = false;
...
#override
Widget build(BuildContext context){
...
TextFormField(
...
autovalidate: true,
validator: (String txt){
if (txt.length == 10){
setState((){
_btnEnabled = true;
});
} else {
setState((){
_btnEnabled = false;
});
}
}
...
FlatButton(
onPressed: _btnEnabled == true ? yourCallback : null,
child: ...
you can use Flutter Reactive Forms. It's a model-driven approach to handling Forms inputs and validations, heavily inspired in Angular's Reactive Forms.
It's a very simple to use libray and in the documentation there is a section that explains how to Enable/Disable Submit button based on the validity of the entire form, not just a field.
The accepted answer seems to not work using the latest Flutter v1.7.8 (stable), it gives me the following error:
This TestForm widget cannot be marked as needing to build because the framework is already in the process of building widgets
The working version looks like the following:
...
autovalidate: true,
validator: (String txt){
bool isValid = txt.length == 10;
if (isValid != _btnEnabled) {
WidgetsBinding.instance.addPostFrameCallback((_) {
setState(() {
_btnEnabled = txt.length == 10;
});
});
}
}
...
You can use this method .
bool isEnable = false;
void validateButton() {
bool isValid = true;
isValid = userEmail.isNotEmpty &&
userPassword.isNotEmpty &&
validateEmail(userEmail) &&
userPassword.length >= 8;
setState(() {
isEnable = isValid;
});
}
now in your Textfield onChanged method you have to call this function
like This
onChanged: (email) {
userEmail = email;
setState(() {});
validateButton();
},
and in your Login Button
isEnable?ActiveButton():DisableButton()
Get error "setState() or markNeedsBuild() called during build." with accepted answer. Just add Future.delayed(Duration.zero).then(....) as a trick solution, it's working on flutter 1.12.13
TextFormField(
...
autovalidate: true,
validator: (String txt){
if (txt.length == 10){
Future.delayed(Duration.zero).then((_){
setState((){
_btnEnabled = true;
});
});
} else {
Future.delayed(Duration.zero).then((_){
setState((){
_btnEnabled = false;
});
});
}
}
....

Resources