Flutter - Provider - Add Map to List Replacing - flutter

Here I need to create a list of maps.
I'm using provider to keep data.
But when I commanded to list.add() it also replacing the 1st element.
Here's my code.
I'm fetching data from firestore collection.
add_inv_stream.dart
class AddInvStream extends StatelessWidget {
const AddInvStream({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
FirebaseServices services = FirebaseServices();
final provider = Provider.of<InventoryProvider>(context);
return StreamBuilder<QuerySnapshot>(
stream: services.inventory
.where('fishType', isEqualTo: provider.inventoryData['fishType'])
.snapshots(),
builder: (context, snapshot) {
if (snapshot.hasError) {
return const Center(child: Text('Something wrong!'));
}
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator());
}
if (snapshot.data!.size == 0) {
return const Center(
child: Text('No inventories'),
);
}
return AddInvData(snapshot: snapshot, services: services);
},
);
}
}
add_inv_data.dart
class AddInvData extends StatefulWidget {
final AsyncSnapshot<QuerySnapshot<Object?>> snapshot;
final FirebaseServices services;
const AddInvData({Key? key, required this.snapshot, required this.services})
: super(key: key);
#override
State<AddInvData> createState() => _AddInvDataState();
}
class _AddInvDataState extends State<AddInvData> {
List abc = [];
#override
Widget build(BuildContext context) {
final providerr = Provider.of<InventoryProvider>(context);
return ListView.builder(
padding: const EdgeInsets.all(15.0),
physics: const ScrollPhysics(),
shrinkWrap: true,
itemCount: widget.snapshot.data!.size,
itemBuilder: (context, index) {
Map<String, dynamic> sellerData =
widget.snapshot.data!.docs[index].data() as Map<String, dynamic>;
return InkWell(
onTap: () {
print('Date: ${sellerData['date']} | QTY: ${sellerData['qty']}');
showDialog(
context: context,
builder: (context) {
return Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(40),
),
elevation: 16,
child: Form(
key: _formkey,
child: Container(
padding: const EdgeInsets.all(20),
child: TextButton(
onPressed: () {
setState(() {
providerr.getInvSellerData(
sellerDate1: sellerData['date'],
sellerQty1: sellerData['qty'],
);
});
print(providerr.inventorySellerData);
abc.add(providerr.inventorySellerData);
print(abc);
},
child: const Text('ASSIGN'),
),
),
),
);
},
);
},
child: Padding(
padding: const EdgeInsets.fromLTRB(10, 0, 10, 30),
child: Container(
padding: const EdgeInsets.all(15),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
border: Border.all(color: Colors.black),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(sellerData['date']),
Text('${sellerData['qty']} kg'),
],
),
),
),
);
},
);
}
}
inv_provider.dart
class InventoryProvider with ChangeNotifier {
Map<String, dynamic> inventorySellerData = {};
getInvSellerData({
String? sellerDate1,
String? sellerQty1,
}) {
if (sellerDate1 != null) {
inventorySellerData['sellerDate1'] = sellerDate1;
}
if (sellerQty1 != null) {
inventorySellerData['sellerQty1'] = sellerQty1;
}
notifyListeners();
}
}
There are only two collections I have created and when I tapped on first container it's printingDate: 10/31/2022 | QTY: 50and a dialog is showing.
Then I clicked assign button it's printing
{sellerDate1: 10/31/2022, sellerQty1: 50}
[{sellerDate1: 10/31/2022, sellerQty1: 50}]
After that I clicked on second container it's printing
Date: 11/25/2022 | QTY: 54and a dialog is showing same as first container.
Then I clicked assign button it's printing
{sellerDate1: 11/25/2022, sellerQty1: 54}
[{sellerDate1: 11/25/2022, sellerQty1: 54}, {sellerDate1: 11/25/2022, sellerQty1: 54}]
I need to get printed when clicked assign button
[{sellerDate1: 10/31/2022, sellerQty1: 50}, {sellerDate1: 11/25/2022, sellerQty1: 54}]
How can I do that?
Why is this replacing all the elements in the list?

how about add map to list abc outside of dialog.
onTap: () {
print('Date: ${sellerData['date']} | QTY: ${sellerData['qty']}');
showDialog(
context: context,
builder: (context) {
return Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(40),
),
elevation: 16,
child: Form(
key: _formkey,
child: Container(
padding: const EdgeInsets.all(20),
child: TextButton(
onPressed: () {
// no need call setState. bacause you already update state by provider
providerr.getInvSellerData(
sellerDate1: sellerData['date'],
sellerQty1: sellerData['qty'],
);
print(providerr.inventorySellerData);
},
child: const Text('ASSIGN'),
),
),
),
);
},
);
// add here
abc.add(providerr.inventorySellerData);
print(abc);
},

Related

Flutter - Provider - Clearing Data itself when navigate

When I in a page and added some quantity and navigate to another page and come back to added more quantity data is cleared.
Here's my code.
add_inv_stream.dart
class AddInvStream extends StatelessWidget {
const AddInvStream({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
FirebaseServices services = FirebaseServices();
final provider = Provider.of<InventoryProvider>(context);
return StreamBuilder<QuerySnapshot>(
stream: services.inventory
.where('fishType', isEqualTo: provider.inventoryData['fishType'])
.where('status', isEqualTo: true)
.snapshots(),
builder: (context, snapshot) {
if (snapshot.hasError) {
return const Center(child: Text('Something wrong!'));
}
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator());
}
if (snapshot.data!.size == 0) {
return const Center(
child: Text('No inventories'),
);
}
return AddInvData(snapshot: snapshot, services: services);
},
);
}
}
add_inv_data.dart
class AddInvData extends StatefulWidget {
final AsyncSnapshot<QuerySnapshot<Object?>> snapshot;
final FirebaseServices services;
const AddInvData({Key? key, required this.snapshot, required this.services})
: super(key: key);
#override
State<AddInvData> createState() => _AddInvDataState();
}
class _AddInvDataState extends State<AddInvData> {
final _qty = TextEditingController();
List sellerList = [];
#override
Widget build(BuildContext context) {
final providerr = Provider.of<InventoryProvider>(context);
return ListView.builder(
padding: const EdgeInsets.all(15.0),
physics: const ScrollPhysics(),
shrinkWrap: true,
itemCount: widget.snapshot.data!.size,
itemBuilder: (context, index) {
Map<String, dynamic> sellerData =
widget.snapshot.data!.docs[index].data() as Map<String, dynamic>;
int sellerQty = int.parse(sellerData['qty']);
return InkWell(
onTap: () {
showDialog(
context: context,
useRootNavigator: false,
builder: (context) {
return Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(40),
),
elevation: 16,
child: Container(
padding: const EdgeInsets.all(20),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('Quantity in kg: '),
const SizedBox(width: 10),
Container(
height: 60,
width: 60,
decoration: BoxDecoration(
border: Border.all(color: Colors.black),
),
child: TextFormField(
controller: _qty,
textAlign: TextAlign.center,
keyboardType: TextInputType.number,
decoration: const InputDecoration(
border: InputBorder.none,
),
),
),
],
),
const SizedBox(height: 50),
TextButton(
onPressed: () async {
Map<String, dynamic> seller = {
'date': sellerData['date'],
'qty': _qty.text,
};
sellerList.add(seller);
providerr.getData(sellerList: sellerList);
print(providerr.inventoryData['sellerList']);
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => const InvDetails(),
));
},
child: const Text('ASSIGN'),
),
],
),
),
);
},
);
},
child: Padding(
padding: const EdgeInsets.fromLTRB(10, 0, 10, 30),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
sellerData['date'],
style: const TextStyle(fontSize: 18),
),
Text(
'${sellerData['qty']} kg',
style: const TextStyle(fontSize: 18),
),
],
),
),
);
},
);
}
}
inv_details.dart
class InvDetails extends StatelessWidget {
const InvDetails({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: TextButton(
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => const AddInv(),
));
},
child: const Text('Add Inventory'),
),
),
);
}
}
inv_provider.dart
class InventoryProvider with ChangeNotifier {
Map<String, dynamic> inventoryData = {};
getData({List? sellerList}) {
if (sellerList != null) {
inventoryData['sellerList'] = sellerList;
}
notifyListeners();
}
}
Here printing at the first
[{date: 10/31/2022, qty: 1}]
When I navigate to InvDetails from AddInvData and when the button is clicked it's printing
[{date: 11/25/2022, qty: 1}]
Data is not updating
But if I didn't navigate.
i.e If I stay in AddInvData and added quantity it is updating.
inv_data.dart (Added textbutton part only ) removed navigate
TextButton(
onPressed: () async {
Map<String, dynamic> seller = {
'date': sellerData['date'],
'qty': _qty.text,
};
sellerList.add(seller);
providerr.getData(sellerList: sellerList);
print(providerr.inventoryData['sellerList']);
},
prints
[{date: 10/31/2022, qty: 1}]
[{date: 10/31/2022, qty: 1}, {date: 11/25/2022, qty: 1}]
Why this is not hapenning when navigate and come back to previous page?

How to pass Stream data through Navigator in Flutter? (Flutter, Dart, Stream Firebase)

I'm building a chatapp which displays all the available chats as ChatTiles.
A ChatTile shows the name and the last message from the chat using a Stream from Firebase.
By clicking on a ChatTile the Navigator pushes a ConversationScreen Widget.
I would like to somehow pass the stream data along the widget tree to the ConversationScreen. So whenever a message is inserted, the ChatTile shows the last message and the ConversationScreen as well.
But my error is this:
Stream has already been listened to.
Here's a picture:
ChatTiles
ChatTile:
class _ChatRoomTileState extends State<ChatRoomTile> {
Stream<QuerySnapshot> chatRoomStream;
DataFromMessages dataFromMessages;
List<Message> messages;
#override
void initState() {
chatRoomStream =
DB_Service.streamChatRooms(context, widget.dataFromChatRoom.chatRoomId);
getUser();
super.initState();
}
#override
Widget build(BuildContext context) {
if (chatRoomStream == null) return Container();
return StreamProvider<QuerySnapshot>.value(
value: chatRoomStream,
initialData: null,
builder: (context, f) {
QuerySnapshot snapshot = Provider.of<QuerySnapshot>(context);
if (snapshot == null) return Container();
dataFromMessages =
dataFromMessagesFromJson(json.encode(snapshot.docs.first.data()));
messages = dataFromMessages.messages.entries
.map((e) => e.value)
.toList()
.reversed
.toList();
return GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ConversationScreen(
dataFromChatRoom: widget.dataFromChatRoom,
uid: widget.uid,
chatRoomStream: chatRoomStream,
),
),
);
},
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 8),
margin: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
border: Border.all(color: Colors.grey, width: 0.5),
borderRadius: BorderRadius.circular(8),
),
child: Row(
...
),
),
);
},
);
}
}
The pushed ConversationScreen:
class _ConversationScreenState extends State<ConversationScreen> {
TextEditingController messageController = TextEditingController();
DataFromMessages dataFromMessages;
List<Message> messages;
#override
Widget build(BuildContext context) {
print("Building ConversationScreen");
if (widget.chatRoomStream == null) return Container();
return StreamBuilder(
stream: widget.chatRoomStream.asBroadcastStream(),
initialData: null,
builder: (context, snap) {
//QuerySnapshot snap = Provider.of<QuerySnapshot>(context);
if (snap == null) return Text(" empty");
dataFromMessages = dataFromMessagesFromJson(
json.encode(snap.data.docs.first.data()));
messages = dataFromMessages.messages.entries
.map((e) => e.value)
.toList()
.reversed
.toList();
return GestureDetector(
onTap: () => FocusScope.of(context).unfocus(),
child: Scaffold(
appBar: buildAppBar(context),
body: Column(
children: [
Expanded(
child: messages != null
? ListView.builder(
shrinkWrap: true,
itemCount: messages.length,
itemBuilder: (context, index) {
return ChatTile(
data:
messages[index].data == widget.uid ? 1 : 0,
message: messages[index].message,
timestamp: messages[index].timestamp,
bubbleNip: BubbleNip.no,
);
})
: Container(),
),
TextInput(
uid: widget.uid,
chatRoomId: widget.dataFromChatRoom.chatRoomId,
messages: messages,
),
],
),
bottomNavigationBar: const SizedBox(height: 50),
),
);
});
}
AppBar buildAppBar(BuildContext context) {
return AppBar(
backgroundColor: Colors.transparent,
elevation: 0,
title: Text(
"Chat with Somebody",
style: TextStyle(
color: Theme.of(context).indicatorColor,
),
),
leading: BackButton(color: Theme.of(context).indicatorColor),
);
}
}

Flutter Cubit fetching and displaying data

I'm trying to fetch data from Genshin API, code below is working, but only with delay (in GenshinCubit class), it looks weard, because I don't know how much time to set for delay. I think, there is a problem in code, cause it must not set the GenshinLoaded state before the loadedList is completed. Now, if I remove the delay, it just sets the GenshinLoaded when the list is still in work and not completed, await doesn't help. Because of that I get a white screen and need to hot reload for my list to display.
class Repository {
final String characters = 'https://api.genshin.dev/characters/';
Future<List<Character>> getCharactersList() async {
List<Character> charactersList = [];
List<String> links = [];
final response = await http.get(Uri.parse(characters));```
List<dynamic> json = jsonDecode(response.body);
json.forEach((element) {
links.add('$characters$element');
});
links.forEach((element) async {
final response2 = await http.get(Uri.parse(element));
dynamic json2 = jsonDecode(response2.body);
charactersList.add(Character.fromJson(json2));
});
return charactersList;
}
}
class GenshinCubit extends Cubit<GenshinState> {
final Repository repository;
GenshinCubit(this.repository) : super(GenshinInitial(),);
getCharacters() async {
try {
emit(GenshinLoading());
List<Character> list = await repository.getCharactersList();
await Future<void>.delayed(const Duration(milliseconds: 1000));
emit(GenshinLoaded(loadedList: list));
}catch (e) {
print(e);
emit(GenshinError());
}
}
}
class HomeScreen extends StatelessWidget {
final userRepository = Repository();
HomeScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return BlocProvider<GenshinCubit>(
create: (context) => GenshinCubit(userRepository)..getCharacters(),
child: MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(body: Container(child: const CharactersScreen())),
),
);
}
}
class CharactersScreen extends StatefulWidget {
const CharactersScreen({
Key? key,
}) : super(key: key);
#override
State<CharactersScreen> createState() => _CharactersScreenState();
}
class _CharactersScreenState extends State<CharactersScreen> {
#override
Widget build(BuildContext context) {
return Column(
children: [
BlocBuilder<GenshinCubit, GenshinState>(
builder: (context, state) {
if (state is GenshinLoading) {
return Center(
child: CircularProgressIndicator(),
);
}
if (state is GenshinLoaded) {
return SafeArea(
top: false,
child: Column(
children: [
Container(
color: Colors.black,
height: MediaQuery.of(context).size.height,
child: ListView.builder(
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemCount: state.loadedList.length,
itemBuilder: ((context, index) {
return Padding(
padding: const EdgeInsets.symmetric(
vertical: 50.0, horizontal: 50),
child: GestureDetector(
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => CharacterDetailsPage(
character: state.loadedList[index],
),
),
),
child: Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
color: Colors.blueAccent.withOpacity(0.3),
borderRadius: const BorderRadius.all(
Radius.circular(
30,
),
)),
child: Align(
alignment: Alignment.bottomRight,
child: Padding(
padding: const EdgeInsets.only(
right: 30.0, bottom: 30),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.end,
children: [
Text(
state.loadedList[index].name
.toString(),
style: TextStyle(
color: Colors.black,
fontSize: 50),
),
RatingBarIndicator(
itemPadding: EdgeInsets.zero,
rating: double.parse(
state.loadedList[index].rarity
.toString(),
),
itemCount: int.parse(
state.loadedList[index].rarity
.toString(),
),
itemBuilder: (context, index) =>
Icon(
Icons.star_rate_rounded,
color: Colors.amber,
))
],
),
),
),
),
),
);
})),
),
],
),
);
}
if (state is GenshinInitial) {
return Text('Start');
}
if (state is GenshinError) {
return Text('Error');
}
return Text('Meow');
}),
],
);
}
}
I found a solution!
I've got that problem because of forEach. How to wait for forEach to complete with asynchronous callbacks? - there is a solution.

Flutter - Returning to previous page from AppBar is not refreshing the page, with Navigator.pop(context)

I was trying to get the list page refreshed if a method was run on another page. I do pass the context using the push navigation.
I tried to follow these 3 answers Answer 1 Answer 2 and Answer 3 and I am not able to manage the states here.
This is the first list page which needs to be refreshed. It calls a class
class _PageLocalState extends State<PageLocal> {
#override
Widget build(BuildContext context) {
return Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Expanded(
child: SafeArea(
child: ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: widget.allLocal.length,
//padding: const EdgeInsets.only(top: 10.0),
itemBuilder: (context, index) {
return LocalCard(widget.allLocal[index]);
},
)),
)
],
),
);
}
}
The next class:
class LocalCardState extends State<LocalCard> {
FavData localdet;
LocalCardState(this.localdet);
ListTile makeListTile() => ListTile(
contentPadding: EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0),
title: Text(
localdet.name,
style: TextStyle(fontWeight: FontWeight.bold),
),
subtitle: Text(localdet.loc),
trailing: Icon(Icons.keyboard_arrow_right, size: 30.0),
onTap: () => navigateToDetail(localdet),
);
Widget get localCard {
return new Card(
elevation: 4.0,
margin: new EdgeInsets.symmetric(horizontal: 10.0, vertical: 6.0),
child: Container(
child: makeListTile(),
));
}
#override
Widget build(BuildContext context) {
return new Container(
child: localCard,
);
}
navigateToDetail(FavData localdet) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => FavouriteDetailPage(
mndet: localdet,
)));
setState(() {});
}
}
Now this is routing to the final detail page:
class _FavouriteDetailPageState extends State<FavouriteDetailPage> {
bool isFav = false;
FavData mndet;
_FavouriteDetailPageState(this.mndet);
// reference to our single class that manages the database
final dbHelper = DatabaseHelper.instance;
#override
Widget build(BuildContext context) {
Widget heading = new Container(...);
Widget middleSection = new Expanded(...);
Widget bottomBanner = new Container(...);
Widget body = new Column(...);
final makeBottom = Container(
height: 55.0,
child: BottomAppBar(
color: Color.fromRGBO(36, 36, 36, 1.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
new FavIconWidget(mndet),
],
),
),
);
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text('The Details'),
backgroundColor: Color.fromRGBO(36, 36, 36, 1.0),
),
body: Container(
child: Card(
elevation: 5.0,
shape: RoundedRectangleBorder(
side: BorderSide(color: Colors.white70, width: 1),
borderRadius: BorderRadius.circular(10),
),
margin: EdgeInsets.all(20.0),
child: Padding(
padding: new EdgeInsets.symmetric(vertical: 16.0, horizontal: 16.0),
child: body,
),
),
),
bottomNavigationBar: makeBottom,
);
}
void share(BuildContext context, FavData mndet) {
final RenderBox box = context.findRenderObject();
final String shareText = "${mndet.name} - ${mndet.desc}";
Share.share(shareText,
subject: mndet.loc,
sharePositionOrigin: box.localToGlobal(Offset.zero) & box.size);
}
}
class FavIconWidget extends StatefulWidget {
final FavData mnforIcon;
FavIconWidget(this.mnforIcon);
#override
_FavIconWidgetState createState() => _FavIconWidgetState();
}
class _FavIconWidgetState extends State<FavIconWidget> {
final dbHelper = DatabaseHelper.instance;
Future<bool> get isFav async {
final rowsPresent = await dbHelper.queryForFav(widget.mnforIcon.id);
if (rowsPresent > 0) {
print('Card Loaded - Its Favourite already');
return false;
} else {
print('Card Loaded - It is not favourite yet');
return true;
}
}
void _insert() async {...}
void _delete() async {...}
#override
Widget build(BuildContext context) {
return FutureBuilder<bool>(
future: isFav,
initialData:
false, // you can define an initial value while the db returns the real value
builder: (context, snapshot) {
if (snapshot.hasError)
return const Icon(Icons.error,
color: Colors.red); //just in case the db return an error
if (snapshot.hasData)
return IconButton(
icon: snapshot.data
? const Icon(Icons.favorite_border, color: Colors.white)
: Icon(Icons.favorite, color: Colors.red),
onPressed: () => setState(() {
if (!snapshot.data) {
print('Its favourite so deleting it.');
_delete();
} else {
print('Wasnt fav in the first place so inserting.');
_insert();
}
}));
return CircularProgressIndicator(); //if there is no initial value and the future is not yet complete
});
}
}
I am sure this is just some silly coding I have done but just not able to find out. Where.
I tried adding Navigator.pop(context); in different sections of the detail page and it fails.
Currently, I have to navigate back to the Favourites list page and then HomePage and then back to Favourites ListPage to refresh the list.
try this.. Anywhere you are using Navigator.pop or Navigator.push .. Instead of this use this:
Navigator.pushReplacement(context,
MaterialPageRoute(builder: (BuildContext context) => Password())
);
//instead of Password use the name of the page(the second page you want to go to)

Add search form above Firestore list in Flutter

I am trying to render a search form above a list of items from Firestore and filter locally based on what is typed in the form.
I tried adding both widgets to the body like this, but it is only displaying the search form:
body: Column(
children: <Widget>[Searchform(), ContentWidget()],
),
This is the current code which displays a basic list:
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
class Items extends StatefulWidget {
Items({Key key}) : super(key: key);
#override
_ItemsState createState() => _ItemsState();
}
class _ItemsState extends State<Items> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Search'),
),
body: ContentWidget(),
);
}
}
class Searchform extends StatelessWidget {
final TextEditingController _searchController = TextEditingController();
#override
Widget build(BuildContext context) {
return TextField(
controller: _searchController,
decoration: InputDecoration(
labelText: "Search",
hintText: "Search",
prefixIcon: Icon(Icons.search),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(15.0),
),
),
),
);
}
}
class ContentWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection('content').snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) return new Text('Error: ${snapshot.error}');
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return new Text('Loading...');
default:
return new ListView(
children:
snapshot.data.documents.map((DocumentSnapshot document) {
return new ListTile(
title: new Text(document['term']),
);
}).toList(),
);
}
},
);
}
}
What I was thinking of doing is saving the items in local state and filter them based on what is typed in the search box.
this is a very simple way try this code within "snapshot.data.documents.map((DocumentSnapshot document)"
if(_searchController.text.toString().contains(document['term'])){
return new ListTile(
title: new Text(document['term']),
);
}
I have provide simple filter record in listview code.
class FilterDemo extends StatefulWidget {
#override
State<StatefulWidget> createState() {
// TODO: implement createState
return FilterState();
}
}
class FilterState extends State<FilterDemo> {
List<String> items, duplicateList;
TextEditingController editingController = TextEditingController();
#override
void initState() {
// TODO: implement initState
super.initState();
items = List<String>.generate(1000, (i) => "Item $i");
duplicateList = items;
}
void filterSearchResults(String query) {
List<String> dummySearchList = List<String>();
dummySearchList.addAll(duplicateList);
if (query.isNotEmpty) {
List<String> dummyListData = List<String>();
dummySearchList.forEach((item) {
if (item.contains(query)) {
dummyListData.add(item);
}
});
setState(() {
items.clear();
items.addAll(dummyListData);
});
return;
} else {
setState(() {
items.clear();
items.addAll(duplicateList);
});
}
}
#override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text("Filter Demo"),
),
body: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
onChanged: (value) {
filterSearchResults(value);
},
controller: editingController,
decoration: InputDecoration(
labelText: "Search",
hintText: "Search",
prefixIcon: Icon(Icons.search),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(25.0)))),
),
),
Expanded(
child: ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return ListTile(
title: Text('${items[index]}'),
);
},
),
),
],
),
);
}
}
I have provide Code how the saving the items in local state and filter them based on what is typed in the search box.
class UserList extends StatefulWidget {
final FirebaseUser user;
final String currentUserId;
UserList({this.currentUserId, this.user});
#override
_UserListState createState() => _UserListState();
}
class _UserListState extends State<UserList> {
TextEditingController _signUpConfirmPassword = new TextEditingController();
String _myValue = '';
UniqueKey _myKey = UniqueKey();
#override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
middle: Text("UserList"),
),
child: ListView(
shrinkWrap: true,
children: <Widget>[
Padding(
padding: EdgeInsets.all(10.0),
child: CupertinoTextField(
keyboardType: TextInputType.text,
//inputFormatters: [LengthLimitingTextInputFormatter(60)],
placeholder: 'Search For..',
// placeholderStyle: TextStyle(
// fontWeight: FontWeight.w200
// ),
prefix: Padding(
padding: EdgeInsets.only(left: 10.0),
child: Icon(
Icons.search,
),
),
onChanged: (val) {
if (val.isNotEmpty) {
_myValue = val;
}
setState(() {
_myKey = UniqueKey();
});
},
decoration: BoxDecoration(
border: Border.all(color: primaryColor),
borderRadius: BorderRadius.circular(20.0)),
)),
SizedBox(height: 10.0),
Container(
key: _myKey,
child: FetchUsers(
user: widget.user,
myValue: _myValue,
)),
],
));
}
}
class FetchUsers extends StatefulWidget {
final String myValue;
final FirebaseUser user;
FetchUsers({this.myValue, this.user});
#override
_FetchUsersState createState() => _FetchUsersState();
}
class _FetchUsersState extends State<FetchUsers> {
List searchName = List();
List userName = List();
Future listOfUsers() {
if (widget.myValue.isEmpty) {
return Firestore.instance
.collection('users')
.where('Role', isEqualTo: 'user')
.orderBy('Created', descending: true)
.limit(10)
.getDocuments()
.then((d) {
userName.clear();
d.documents.forEach((f) {
userName.add(f);
});
return userName;
});
} else {
return Firestore.instance
.collection('users')
.where('Role', isEqualTo: 'user')
.limit(10)
.getDocuments()
.then((d) {
searchName.clear();
d.documents.forEach((f) {
if (f.data['Name']
.toString()
.toLowerCase()
.contains(widget.myValue.toLowerCase())) {
searchName.add(f);
}
});
return searchName;
});
}
}
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: listOfUsers(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(
child: CupertinoActivityIndicator(),
);
} else {
return ListView.separated(
physics: ClampingScrollPhysics(),
separatorBuilder: (context, int) {
return Divider();
},
itemCount: snapshot.data.length,
shrinkWrap: true,
padding: EdgeInsets.all(10.0),
itemBuilder: (context, index) {
return Card(
elevation: 7.0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0)),
child: IntrinsicHeight(
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
' ${snapshot.data[index]['Name']}',
style: TextStyle(
color: outlineColor,
fontWeight: FontWeight.bold),
),
SizedBox(
height: 5.0,
),
Text(
' ${snapshot.data[index]['Email']}',
),
],
),
Spacer(),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
RaisedButton.icon(
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(20.0)),
color: primaryColor,
onPressed: () {
Navigator.push(
context,
CupertinoPageRoute(
builder: (context) => Chat(
user: widget.user,
name: snapshot.data[index]
['Name'],
peerId: snapshot.data[index]
['UID'],
)));
},
icon: Icon(
Icons.chat,
color: themeColor,
),
label: Text(
"Chat",
style: TextStyle(color: themeColor),
)),
RaisedButton.icon(
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(20.0)),
color: primaryColor,
onPressed: () {
Navigator.push(
context,
CupertinoPageRoute(
builder: (context) =>
SendNotificationOption(
name: snapshot.data[index]
['Name'],
myFcm: snapshot.data[index]
['UID'],
isBroadcast: false,
)));
},
icon: Icon(
Icons.notifications,
color: themeColor,
),
label: Text(
"Notification",
style: TextStyle(color: themeColor),
)),
],
),
],
),
),
));
},
);
}
},
);
}
}
What you have type in Search then that Data is shown in listview]1