I have a Stream Builder which populates a Stack of cards:
_showCards() {
return StreamBuilder<QuerySnapshot>(
stream: cardReference.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return circularProgress();
}
return Stack(children: fillCards(snapshot));
});
}
fillCards(AsyncSnapshot<QuerySnapshot> snapshot) {
return snapshot.data.documents
.map((doc) => buildCards(
image: doc["mediaUrl"],
title: doc["title"],
type: doc["description"],
))
.toList();
}
I want to remove the top snapshot on the Stack with a skip button. How could I manage the snapshots to access a certain index?
Edit:
I need to remove the card from the Stack view, not actually delete it from the database. I'm thinking I should use a List and use .removeAt(index), but not sure how to add snapshots from Firestore to a list. I currently have a map of documents as you can see in fillCards().
Widget buildCards({image, title, type}) {
return Column(
children: <Widget>[
// UI showing Image Url, title and description in a Card.
// then I have an icon, to skip the card on top and show the one behind
IconButton(
icon: Icon(FontAwesomeIcons.forward,
color: Colors.greenAccent, size: 21),
onPressed: () => //SKIP CARD
It seems you are trying to skip any item of the list received when tapping the skip button of the item.
Here are some ways to do this:
If the list is particular from a user, you could mark the item on the
database as "skipped" and when you show the list, just show the items
that aren't "skipped".
If the list could be shared with different users, you could create another list for each user, with "skipped" ids. Then show the items whose ids aren't in that user "skipped" list.
If you want to handle this on client side, without altering the database, you could create a list of "skipped" ids and when you show the list, just show the items that aren't on that "skipped" list.
Here is an idea for the last option:
final _skippedIds = List();
// The filtered list
snapshot.data.documents.where((doc) => !_skippedIds.contains(doc["id"])).map(...
// The onTap of each skip button:
onTap: () => setState(() => _skippedIds.add(doc["id"])),
Also, you could save on SharedPreferences the list of skipped ids.
Were I you in that situation, I make a viewModel and copy data of documents to the viewModel. Then I only modify the viewModel to manage views.
Related
I have one longer form and save button at bottom of form. when user taps on save button, form field validator highlights error text based on validator() function. my problem is when there is any error into form, page should be scroll to that error widget(TextFormField, Checkbox, Slider or any Custom form field).
I tried with FocusScope.of(context).requestFocus(focus_node); but its not scrolling.
I also tried with ScrollController like this,
final RenderBox renderBoxRed = key.currentContext.findRenderObject();
final positionRed = renderBoxRed.localToGlobal(Offset.zero);
scrollController.animateTo(positionRed.distance, duration: Duration(milliseconds: 300), curve: Curves.easeIn);
but its always scrolling to top of the screen.
Another scenario is I have terms and condition screen where there is longer text and at the end of terms text, I added checkbox and after that again some other longer text is there. and I added button on top of screen. if user press that button before checking that terms checkbox, screen should be scroll to that checkbox to highlight checkbox so user can know that terms and condition agreement is required.
How to achieve that with Flutter? is there any way to auto scroll to required field when form.currentState.validate() fails??
Well you can use focus node to requestFocus in the field, when it is invalid. Something like this.
First create a focus node for each field like this.
FocusNode phone = FocusNode();
Then create a validator class.
class VONPhoneValidator extends TextFieldValidator {
final FocusNode focusNode;
VONPhoneValidator(this.focusNode,
{String errorText = 'Enter a valid phone number'})
: super(errorText);
#override
bool get ignoreEmptyValues => true;
#override
bool isValid(String value) {
if (hasMatch(r'^[0-9]{10}$', value)) {
return true;
} else {
focusNode.requestFocus();
return false;
}
}
}
And this is going to be your field,
TextFormField(
maxLengthEnforced: true,
keyboardType: TextInputType.phone,
controller: _phoneController,
focusNode: phone,
validator: VONPhoneValidator(phone, errorText: "Enter Valid Phone Number"),
decoration: InputDecoration(
prefixIcon: CountryCodePicker(
hideMainText: true,
initialSelection: 'NP',
favorite: ['NP', 'IN'],
showCountryOnly: true,
showFlagMain: true,
flagWidth: 20,
boxDecoration: BoxDecoration(color: Colors.white),
onChanged: (value) {
_formController.country.value = value.toString();
},
),
labelText: 'Phone Number',
border: OutlineInputBorder(borderSide: BorderSide()),
),
);
Flutter has an opened issue for this https://github.com/flutter/flutter/issues/58877.
Didier has a very good workaround to solve this https://www.didierboelens.com/2018/04/hint-4-ensure-a-textfield-or-textformfield-is-visible-in-the-viewport-when-has-the-focus/.
Based on the Didier code, i've made a package and publish on Pub.dev. https://pub.dev/packages/ensure_visible_when_focused
So I have a normal TextField with which I filter a list
children: products.map((doc) => _buildSingleProduct(doc)).toList(),, it works as it should, then I added to it a text-to-speech pluugin speech_recognition: and the combined it with the filtering function, It works all fine.
The problem is when I finish with the speech filtering then I for example want to add or make corrections to it with writing to the TextField it doesn't filter anymore.
Textfield
child: TextField(
controller: controller,
decoration: InputDecoration(
labelText: allTranslations.text(StringConstant.search),
prefixIcon: Icon(Icons.search),
suffixIcon: IconButton(
icon: Icon(Icons.mic),
onPressed: () {
if (_isAvailable && !_isListening)
_speechRecognition
.listen(locale: "en_US")
.then((result) => print('$result'));
},
),
),
),
As you can see there is the controller which I use to filter, and then the mic icon to pass the result from the speech to the controller like this:
_speechRecognition
.setRecognitionResultHandler((String result) => setState(() {
controller = TextEditingController(text: resultText = result);
}));
here I get the result from the speech and add it to the resultText of the filter and the controller so it appears in the textField.
if I do it like this:
_speechRecognition
.setRecognitionResultHandler((String speech) => setState(() => resultText = speech));
it works all fine but the text does not appear in the text-field obviously.
for the textField filtering I init the state to add it to the resultText:
initState() {
initSpeechRecognizer();
controller.addListener(() {
setState(() {
resultText = controller.text;
});
});
super.initState();
}
this is how I return the result from the db:
return resultText == null || resultText == ""
? buildProducts(id, title, favorite, message, price, doc)
: doc.data['title'].toLowerCase().contains(resultText.toLowerCase())
? buildProducts(id, title, favorite, message, price, doc)
: Container();
as you can probably see I search the title.
So the problem one more time,
1.search with speech
it appears on the textField and filters the list
when I press the textField to change the query it doesn't filter anymore.
But the other way around works
filter the list with text
it filters the list
I activate speech-to-text and it changes the query and filters the list with the new query.
So for people who need the solution
_speechRecognition
.setRecognitionResultHandler((String result) => setState(() {
resultText = result;
controller.text = resultText;
}));
you get the result from the speech, add this to the handling variable, but you also than add that result to the controller so you get the result at the textField.
In their example https://flutter.dev/docs/cookbook/plugins/picture-using-camera we can take pictures using the camera plugin.
I modified the code and move into a separate widget. My main goal is to try to implement a picture area (like QRCode style) and take the picture and if necessary tell the user to corp the image or my be app will do it automatically. There is a barcode_scan plugin. It shows an area to scan the barcode. I like to implement that part to take pictures of an item.
https://codecanyon.net/item/qr-code-barcode-scanner-and-generator-for-ios-swift-with-admob/screenshots/20280521?index=1 screenshot2 has a 4 half square bracket on 4 edges. I like to make it similar but capture images only.
I am new to this plugin and corp idea. How can I create a picture area in Flutter so the user can center the item in that area and take a picture.?
Widget _buildPictureArea(BuildContext context) {
return new Container(
width: 200,
height: 200,
child: FutureBuilder<void>(
future: _initializeControllerFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
// If the Future is complete, display the preview
return CameraPreview(_controller);
} else {
// Otherwise, display a loading indicator
return Center(child: CircularProgressIndicator());
}
},
),
);
}
I'm filtering my list of my GridView.builder like this:
onSearchTextChanged(String text) async {
if (text.isEmpty) {
_searchList = _productList.toList();
setState(() {
});
return;
}
_searchList = _productList.where((product) => product.name.toLowerCase().contains(text.toLowerCase()) ||
product.type.toLowerCase().contains(text.toLowerCase())).toList();
setState(() {});
}
but when im typing on the textfield the performance just go down, exactly to 2.5 fps sometimes when im deleting the text or typing to fast.
This is my Gridview builder
GridView.builder(
primary: false,
shrinkWrap: true,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: itemWidth / itemHeight,
),
itemCount: _searchList.length,
itemBuilder: (BuildContext context, int index) {
return _searchList[index];
}));
Always set state variables inside the setState() call.
Make your onSearchTextChanged() function save the search text and start a Future.delayed() that performs the search and update after a short delay. See: https://stackoverflow.com/a/54686588/1736338 .
You can use a Suffix Tree data structure to speed up the search operation. Unfortunately, I couldn't find one written in Dartlang. You could code one. The trie package is unsuitable since it supports only Set functionality, not Map functionality.
I am creating an ExtJS MVC application with a dynamic menu. I have several menu elements which will call the same screen (set an active card in a layout) but need to pass a different value in as a parameter each time. So that one card can display different data depending on the parameter which will act as a filter.
my menu elements have a click listener:
listeners: {
itemclick: function(view, record, item, index, e){
Ext.getCmp('contentpanel').layout.setActiveItem(record.getId());
}
}
the record Id will be the card I am setting as active.
How can I pass along a parameter to the card?
You could just add another attribute to the Panel if you want. For example:
Ext.define('YourApp.view.YourCardPanel' ,{
extend: 'Ext.panel.Panel',
id: 'contentpanel',
alias : 'widget.yourcardpanel',
layout: 'card',
newParam: null, // Just to know that this attribute exists but there is no need to declare it.
items: [],
changeLayout: function(){
if (this.newParam == 'new value') {
// Do your stuff
}
}
});
And then you could change the value of that parameter.
listeners: {
itemclick: function(view, record, item, index, e){
var cardPanel = Ext.getCmp('contentpanel');
cardPanel.newParam = 'new value';
cardPanel.changeLayout();
cardPanel.layout.setActiveItem(record.getId());
}
}