Search and select item in listview using flutter - flutter

I am searching in ListView and I am getting search result in flitered list but when I am selecting the searched item in listview and clear the searchbox in the original list my selected item is deselected.
My original list is "rest" list in the code and filtered list is "filteredList used in code.
Help me to solve my issue as I am new to flutter.
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:http/http.dart' as http;
import 'package:shared_preferences/shared_preferences.dart';
String stringValue="default";
String Currentdate;
const lightGrey = Color(0xff858585);
const darkGrey = Color(0xff404042);
const orange = Color(0xffff8500);
const blue = Color(0xff2f5597);
const skyblue=Color(0xffF1F5F9);
const darkblue=Color(0xffD4E7F9);
class AttendencePage2 extends StatefulWidget {
final String centernametext,batchname,date,centerid,batchid,accesstoken;
AttendencePage2(this.centernametext,this.batchname,this.date,this.centerid,this.batchid,this.accesstoken);
#override
State<StatefulWidget> createState() {
// TODO: implement createState
return _AttendencePage2();
}
}
class _AttendencePage2 extends State<AttendencePage2> {
int i;
String str_accesstoken;
List rest;
List<Autogenerated> list= List<Autogenerated>();
List filteredlist;
TextEditingController controller = new TextEditingController();
bool isSelected = false;
List<int> indexList = new List();
bool longPressFlag = false;
void longPress() {
setState(() {
if (indexList.isEmpty) {
longPressFlag = false;
} else {
longPressFlag = true;
}
});
}
var mycolor=Colors.white;
bool checkVal = false;
bool checkVal2=false;
#override
void initState() {
super.initState();
getStringValuesSF();
StudentListRequest();
}
#override
Widget build(BuildContext context) {
// for (var i = 0; i < 50; i++) {
// indexList.add(Element(isSelected: false));
// }
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
systemNavigationBarColor: Colors.white, // navigation bar color
statusBarColor: Colors.black, // status bar color
));
return MaterialApp(
home: Scaffold(
appBar: AppBar(
centerTitle: true,
backgroundColor: orange,
title: Text('ATTENDENCE'),
),body:
Stack(
children: <Widget>[
Container(
color: Colors.white,
),
Container(
color: skyblue,
width: double.infinity,
height: 65,
padding: EdgeInsets.only(right: 20,left: 20,top: 10,bottom: 10),
child:Row(
children: <Widget>[
Container(
child:Column(children: <Widget>[
Text("Center Name",style: TextStyle(color: lightGrey,fontSize: 17)),
Container(
margin: EdgeInsets.only(top:5),
child:Text(widget.centernametext.toUpperCase(),style: TextStyle(color: Colors.black,fontSize: 13)),
),
],)
//child:
),
Spacer(),
Container(
child:Column(children: <Widget>[
Text("Batch",style: TextStyle(color: lightGrey,fontSize: 17),textAlign: TextAlign.left,),
Container(
margin: EdgeInsets.only(top:5),
child:Text(widget.batchname,style: TextStyle(color: Colors.black,fontSize: 13)),),
],)
),
Spacer(),
Container(
child:Column(children: <Widget>[
Text("Date",style: TextStyle(color: lightGrey,fontSize: 17)),
Container(
margin: EdgeInsets.only(top:5),
child:Text(widget.date,style: TextStyle(color: Colors.black,fontSize: 13)),
),
],)
),
Container(
margin: EdgeInsets.only(left: 10),
child: Image.asset('assets/grey_edit.png',width: 20,height: 25),
),
],
)
),
_searchBar(),
Container(
color: skyblue,
width: double.infinity,
height: 50,
margin: EdgeInsets.only(top:155,left: 10,right: 10),
padding: EdgeInsets.only(right: 20,left: 0,top: 10,bottom: 10),
child:Row(
children: <Widget>[
Container(
child: Checkbox(
value: checkVal,
onChanged: (bool value) {
setState(() {
checkVal = value;
if(checkVal==true){
isSelected=true;
}else{
isSelected=false;
}
});
} ),
),
Container(margin: EdgeInsets.only(top:5),
child:Column(children: <Widget>[
Text("Name",style: TextStyle(color: lightGrey,fontSize: 15)),
],)
),
Spacer(),
Container(margin: EdgeInsets.only(top:5),
child:Column(children: <Widget>[
Text(" ",style: TextStyle(color: lightGrey,fontSize: 15),textAlign: TextAlign.left,),
],)
),
Spacer(),
Container(margin: EdgeInsets.only(top:5),
child:Column(children: <Widget>[
Text("Level ",style: TextStyle(color: lightGrey,fontSize: 15)),
],)
),
Spacer(),
Container(margin: EdgeInsets.only(top:5),
child:Column(children: <Widget>[
Text("No. of class",style: TextStyle(color: lightGrey,fontSize: 15)),
],)
),
Spacer(),
Container(margin: EdgeInsets.only(top:5),
child:Column(children: <Widget>[
Text("Attend",style: TextStyle(color: lightGrey,fontSize: 15)),
],)
),
],
)
),
Container(
margin: EdgeInsets.only(top:205,left: 10,right: 10),
decoration: BoxDecoration(
border: Border.all(color: darkblue)
),
child: ListView.builder(
//addAutomaticKeepAlives: true,
itemCount: filteredlist==null?0:filteredlist.length,
// padding: const EdgeInsets.all(2.0),
itemBuilder: (context, index) {
return new CustomWidget(
selected:isSelected,
rest:filteredlist,
index: index,
longPressEnabled: longPressFlag,
callback: () {
longPress();
},
);
})
)])));
}
_searchBar() {
return Container(
child:Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
width: 350,
height: 40,
margin: EdgeInsets.only(left:20,top:90),
child:TextField(
decoration: InputDecoration(
contentPadding: EdgeInsets.fromLTRB(20.0, 15.0, 20.0, 15.0),
prefixIcon: new Padding(
padding: const EdgeInsets.only( top: 13, left: 0, right: 5, bottom: 13),
child: new SizedBox(
height: 2,
child: Image.asset('assets/search.png'),
),
),
labelText: "Search by name",
labelStyle: TextStyle(
color: lightGrey,
fontSize: 15
),
border: OutlineInputBorder( borderSide: BorderSide(color: lightGrey, width: 0.5),
borderRadius: BorderRadius.circular(5.0)),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: orange, width: 0.5),
borderRadius: BorderRadius.circular(5.0)
)),
controller: controller,
onChanged: (string){setState(() {
filteredlist=rest.where((f){
var dataName=f['student']['name'].toString().toLowerCase();
var dataName2=f['course']['level_no'].toString().toLowerCase();
return dataName.contains(string)||dataName2.contains(string);
}).toList();
}
);
},
)
),
],
)
);
}
Future<List<Autogenerated>> StudentListRequest() async {
String as=widget.accesstoken.toString();
var url = 'http://demo.neurapses.com:3032/students?center=5ca5ba30e0adb9c1839aa0d2&batch=5ca5c81597f8a03368df072c';
var response = await http.get(url,
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer $as'
},
);
final int statusCode = response.statusCode;
if (statusCode < 200 || statusCode > 400 || json == null) {
throw new Exception("Error while fetching data");
} else {
setState(() {
var data = json.decode(response.body);
rest = data['docs'];
for(var rest in rest)
{
list.add(Autogenerated.fromJson(rest));
}
filteredlist=rest;
});
return list;
}
}
getStringValuesSF() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
str_accesstoken = prefs.getString('accesstoken');
}
}
class Autogenerated {
List<Docs> docs;
Autogenerated({this.docs});
Autogenerated.fromJson(Map<String, dynamic> json) {
if (json['docs'] != null) {
docs = new List<Docs>();
json['docs'].forEach((v) {
docs.add(new Docs.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.docs != null) {
data['docs'] = this.docs.map((v) => v.toJson()).toList();
}
return data;
}
}
class Docs {
Student student;
Docs(
{
this.student,
});
Docs.fromJson(Map<String, dynamic> json) {
student =
json['student'] != null ? new Student.fromJson(json['student']) : null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.student != null) {
data['student'] = this.student.toJson();
}
return data;
}
}
class Student {
String name;
Student(
{
this.name,
});
Student.fromJson(Map<String, dynamic> json) {
name = json['name'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['name'] = this.name;
return data;
}
}
class CustomWidget extends StatefulWidget {
final int index;
final bool longPressEnabled;
final VoidCallback callback;
final List rest;
bool selected;
CustomWidget({Key key, this.selected, this.rest, this.index, this.longPressEnabled, this.callback}) : super(key: key);
#override
_CustomWidgetState createState() => new _CustomWidgetState();
}
class _CustomWidgetState extends State<CustomWidget> {
final skyblue=Color(0xffF1F5F9);
#override
Widget build(BuildContext context) {
return new GestureDetector(
onLongPress: () {
widget.callback();
},
onTap: () {
if (widget.longPressEnabled) {
widget.callback();
}
},
child:Container(
margin: new EdgeInsets.only(top:5.0),
color: widget.selected ? Colors.grey[300]:Colors.white,
child:Row(children: <Widget>[
Flexible(
fit:FlexFit.loose,
child: ListTile(
contentPadding: EdgeInsets.only(left: 0.0, right: 0.0),
title:
Container(
child:Column(children: <Widget>[
Row(
children: <Widget>[
Container(
child: Checkbox(
onChanged: (val) {
setState(() {
widget.selected = !widget.selected;
});
},
value: widget.selected,
),
),
Container(
child:Container(width:80,child:Text(widget.rest[widget.index]['student']['name'], style: TextStyle(color: Colors
.black, fontSize: 13),
)),
),
Spacer(),
Container(
child: Text(widget.rest[widget.index]['course']['level_no'], style: TextStyle(color: Colors
.black, fontSize: 13),)
),
Spacer(),
Container(
child: Text(
"", style: TextStyle(color: Colors.black,
fontSize: 13),)
),
Spacer(),
Container(
child: Text("", style: TextStyle(color: Colors
.black, fontSize: 13),)
),
],
),
Container(
color: darkblue,
height: 0.7,
width: double.infinity,
),
]),
// onLongPress: toggleSelection,
))
)],),
));
}
}

Add Search Bar
TextField(
controller: editingController,
decoration: InputDecoration(
labelText: "Search",
hintText: "Search",
prefixIcon: Icon(Icons.search),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(25.0)))),
),
Code for UI showing a search bar and ListView with 1000 items
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(title: 'ListView with Search'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
TextEditingController editingController = TextEditingController();
final duplicateItems = List<String>.generate(10000, (i) => "Item $i");
var items = List<String>();
#override
void initState() {
items.addAll(duplicateItems);
super.initState();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: Container(
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
onChanged: (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(
shrinkWrap: true,
itemCount: items.length,
itemBuilder: (context, index) {
return ListTile(
title: Text('${items[index]}'),
);
},
),
),
],
),
),
);
}
}

Related

Provider notifylistener() not working on release mode

I am trying to implement multi-select feature, everything seem to be working well on debug mode including the loading indicators but unfortunately the changes doesn't update(notifyListeners()) on release mode
This is how my viewModel looks like:
class HobbyViewModel extends ChangeNotifier {
bool loading = false;
bool isSelected = false;
List<dynamic> hobbyList = [
'Shopping',
'Swimming',
'Travelling',
'Brunch',
'Music',
'Trips',
'Camping'
];
List<dynamic>? selectedHobby = [];
checkHobbySelected(hobby, UserModel user) {
if (user.hobbies != null) {
selectedHobby = user.hobbies!;
notifyListeners();
}
if (selectedHobby!.contains(hobby)) {
isSelected = true;
notifyListeners();
} else {
isSelected = false;
notifyListeners();
}
}
setHobby(hobby) {
if (!selectedHobby!.contains(hobby)) {
if (selectedHobby!.length < 5) {
selectedHobby!.add(hobby);
// notifyListeners();
}
print('>>>>> $selectedHobby');
notifyListeners();
} else {
selectedHobby!.removeWhere((element) => element == hobby);
print('>>>>> $selectedHobby');
notifyListeners();
}
}
updateHobbies(BuildContext context) async {
loading = true;
notifyListeners();
try {
await usersRef.doc(firebaseAuth.currentUser!.uid).update({
'hobbies': selectedHobby,
});
} catch (e) {
loading = false;
notifyListeners();
}
loading = false;
notifyListeners();
Navigator.pop(context);
}
}
This is the hobby page where I am multi-selecting:
import 'package:quicktext/view_models/profile/hobby_view_model.dart';
class Hobby extends StatefulWidget {
final UserModel user;
const Hobby({Key? key, required this.user}) : super(key: key);
#override
State<Hobby> createState() => _HobbyState();
}
class _HobbyState extends State<Hobby> {
#override
Widget build(BuildContext context) {
HobbyViewModel viewModel =
Provider.of<HobbyViewModel>(context, listen: true);
return Scaffold(
appBar: AppBar(
title: Text(
'What are your Hobbies?',
style: TextStyle(
fontSize: 17.0,
),
),
),
body: LoadingOverlay(
isLoading: viewModel.loading,
progressIndicator: CupertinoActivityIndicator(),
opacity: 0.1,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 10.0),
child: SingleChildScrollView(
child: Wrap(
children: viewModel.hobbyList.map(
(hobby) {
viewModel.checkHobbySelected(hobby, widget.user);
return GestureDetector(
onTap: () => viewModel.setHobby(hobby),
child: Container(
margin: EdgeInsets.symmetric(horizontal: 5, vertical: 4),
child: Container(
padding:
EdgeInsets.symmetric(vertical: 5, horizontal: 12),
decoration: BoxDecoration(
color: viewModel.isSelected
? Color(0xffffb109)
: Colors.white,
borderRadius: BorderRadius.circular(10),
border: Border.all(
color: Colors.grey,
),
),
child: Text(
hobby,
style: TextStyle(
color: viewModel.isSelected
? Colors.white
: Colors.grey,
fontSize: 14,
),
),
),
),
);
},
).toList(),
),
),
),
),
bottomNavigationBar: Padding(
padding: const EdgeInsets.only(bottom: 100.0, right: 20.0, left: 20.0),
child: ClipRRect(
borderRadius: BorderRadius.circular(5.0),
child: Container(
height: 60.0,
color: Theme.of(context).colorScheme.secondary,
child: InkWell(
onTap: () => viewModel.updateHobbies(context),
child: Center(
child: const Text(
'Done',
style: TextStyle(
fontSize: 15.0,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
),
),
),
),
),
);
}
}
Is there anything wrong with my code? I am using provider ^6.0.1

MultiSearch in flutter

The goal of this project is to use Multisearch to search local JSON data based on an int number inside the string. The search for string content has shown the result, now I'm trying to add a search for number entered by the user that searches by int inside string content, but it returns an error.
null isn't subtype of string.
There is a problem with this search code since it works for both string content and integer number.
import 'dart:convert';
import 'package:ebook_flutter_app/constant.dart';
import 'package:ebook_flutter_app/screens/show_item.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:persistent_bottom_nav_bar/persistent-tab-view.dart';
import '../widgets/showImage.dart';
class SearchScreen extends StatefulWidget {
const SearchScreen({Key? key}) : super(key: key);
#override
SearchScreenState createState() => SearchScreenState();
}
class SearchScreenState extends State<SearchScreen> {
List textValues = [];
List original = [];
static TextEditingController txtQuery = TextEditingController();
void loadData() async {
String jsonStr = await rootBundle.loadString('assets/db/text_value.json');
var json = jsonDecode(jsonStr);
textValues = json;
original = json;
setState(() {});
}
void loadImage() async {
String jsonStr = await rootBundle.loadString('assets/db/image_db.json');
var json = jsonDecode(jsonStr);
textValues = json;
original = json;
print('load Image is running....');
setState(() {});
}
void search(String query) {
if (query.isEmpty) {
textValues = original;
setState(() {});
return;
}
query = query.toLowerCase();
print(query);
List result = [];
textValues.forEach((element) {
var name = element["name"].toString().toLowerCase();
var description = element["description"].toString().toLowerCase();
if (name.contains(query) || description.contains(query)) {
result.add(element);
}
});
textValues = result;
setState(() {});
}
void searchById(String query1) {
if (query1.isEmpty) {
textValues = original;
print('query1 is .....$query1');
setState(() {});
return;
}
print('query1 is $query1');
List result = [];
textValues.forEach((element) {
var id_num = element["id_num"].toString();
var id_img = element["id_img"].toString();
if (id_num.contains(query1) ||
id_img.contains(query1)) {
result.add(element);
print('result is......$result');
}
});
textValues = result;
print('textValues is .....$textValues');
setState(() {});
}
#override
void initState() {
super.initState();
txtQuery.text.contains(r'^[0-3]+$') ? loadImage() : loadData();
print('Init State is Loading....');
}
String StrOrInt(String text) {
if (text.toString().startsWith('1') || text.toString().startsWith('2')) {
return 'int';
} else {
return 'str';
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar(2),
body: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
margin: const EdgeInsets.all(10),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextFormField(
controller: txtQuery,
onChanged: search,
textDirection: TextDirection.rtl,
decoration: InputDecoration(
hintText: "جست وجو...",
hintTextDirection: TextDirection.rtl,
hintStyle: TextStyle(
color: Colors.black,
fontSize: 18,
fontFamily: 'iran-sans-ds',
decoration: TextDecoration.none,
fontStyle: FontStyle.italic,
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(4.0)),
focusedBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.black)),
prefixIcon: const Icon(Icons.search),
suffixIcon: IconButton(
icon: const Icon(Icons.clear),
onPressed: () {
txtQuery.text = '';
txtQuery.text.contains(r'^[0-3]+$') ? searchById(txtQuery.text) : search(txtQuery.text);
},
),
),
keyboardType: TextInputType.text,
),
],
),
),
txtQuery.text.isEmpty ? Container() : _listView(textValues)
]),
);
}
}
Widget _listView(text_value) {
return Expanded(
child: ListView.builder(
itemCount: text_value.length,
itemBuilder: (context, index) {
var textVal = text_value[index];
String description = textVal['description'];
String id_num = textVal['id_num'];
String id_img = textVal['id_img'];
print('id_num is ....$id_num' ' id_img is.....$id_img');
return Card(
margin: const EdgeInsets.fromLTRB(8.0, 4.0, 8.0, 4.0),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0)),
color: Colors.blue[50],
child: Theme(
data:
Theme.of(context).copyWith(dividerColor: Colors.transparent),
child: InkWell(
onTap: (() => pushNewScreen(
context,
screen: !textVal['id_num'].toString().contains(r'^[0-3]+$')
? ShowItem(
name: textVal['name'],
description: textVal['description'],
)
: ShowImage(
title: textVal['id_num'],
image: Myasset(textVal['id_img']),
),
withNavBar: true, // OPTIONAL VALUE. True by default.
pageTransitionAnimation:
PageTransitionAnimation.slideRight,
)),
child: ExpansionTile(
title: Text(
!textVal['id_num'].toString().contains(r'^[0-3]+$')
? textVal['name']
: textVal['id_num'],
textDirection: TextDirection.rtl,
style:
const TextStyle(fontSize: 20.0, color: Colors.black54),
),
childrenPadding: const EdgeInsets.only(
bottom: 20.0, right: 20.0, left: 20.0, top: 5.0),
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: !textVal['id_num'].toString().contains(r'^[0-3]+$')
? [
const Text(
'بیشتر',
textDirection: TextDirection.rtl,
textAlign: TextAlign.justify,
style: TextStyle(
color: Colors.blue,
fontWeight: FontWeight.bold),
),
Text(
'${description.substring(0, 39)} ...',
textDirection: TextDirection.rtl,
textAlign: TextAlign.justify,
style: TextStyle(color: Colors.black),
),
]
: [Image.asset(Myasset(textVal['id_img']))],
)
],
),
),
),
);
}),
);
}
Below is the last source code which works with string content and returns the result.
import 'dart:convert';
import 'package:ebook_flutter_app/constant.dart';
import 'package:ebook_flutter_app/screens/show_item.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:persistent_bottom_nav_bar/persistent-tab-view.dart';
class SearchScreen extends StatefulWidget {
const SearchScreen({Key? key}) : super(key: key);
#override
SearchScreenState createState() => SearchScreenState();
}
class SearchScreenState extends State<SearchScreen> {
List textValues = [];
List original = [];
TextEditingController txtQuery = TextEditingController();
void loadData() async {
String jsonStr = await rootBundle.loadString('assets/db/text_value.json');
var json = jsonDecode(jsonStr);
textValues = json;
original = json;
setState(() {});
}
void search(String query) {
if (query.isEmpty) {
textValues = original;
setState(() {});
return;
}
query = query.toLowerCase();
print(query);
List result = [];
textValues.forEach((element) {
var name = element["name"].toString().toLowerCase();
var description = element["description"].toString().toLowerCase();
if (name.contains(query) || description.contains(query)) {
result.add(element);
}
});
textValues = result;
setState(() {});
}
#override
void initState() {
super.initState();
loadData();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar(2),
body: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
margin: const EdgeInsets.all(10),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextFormField(
controller: txtQuery,
onChanged: search,
textDirection: TextDirection.rtl,
decoration: InputDecoration(
hintText: "جست وجو...",
hintTextDirection: TextDirection.rtl,
hintStyle: TextStyle(
color: Colors.black,
fontSize: 18,
fontFamily: 'iran-sans-ds',
decoration: TextDecoration.none,
fontStyle: FontStyle.italic,
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(4.0)),
focusedBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.black)),
prefixIcon: const Icon(Icons.search),
suffixIcon: IconButton(
icon: const Icon(Icons.clear),
onPressed: () {
txtQuery.text = '';
search(txtQuery.text);
},
),
),
keyboardType: TextInputType.text,
),
],
),
),
txtQuery.text.isEmpty ? Container() : _listView(textValues)
]),
);
}
}
Widget _listView(text_value) {
return Expanded(
child: ListView.builder(
itemCount: text_value.length,
itemBuilder: (context, index) {
var textVal = text_value[index];
String description = textVal['description'];
return Card(
margin: const EdgeInsets.fromLTRB(8.0, 4.0, 8.0, 4.0),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0)),
color: Colors.blue[50],
child: Theme(
data:
Theme.of(context).copyWith(dividerColor: Colors.transparent),
child: InkWell(
onTap: (() => pushNewScreen(
context,
screen: ShowItem(
name: textVal['name'],
description: textVal['description'],
),
withNavBar: true, // OPTIONAL VALUE. True by default.
pageTransitionAnimation:
PageTransitionAnimation.slideRight,
)),
child: ExpansionTile(
title: Text(
textVal['name'],
textDirection: TextDirection.rtl,
style:
const TextStyle(fontSize: 20.0, color: Colors.black54),
),
childrenPadding: const EdgeInsets.only(
bottom: 20.0, right: 20.0, left: 20.0, top: 5.0),
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
const Text(
'بیشتر',
textDirection: TextDirection.rtl,
textAlign: TextAlign.justify,
style: TextStyle(
color: Colors.blue, fontWeight: FontWeight.bold),
),
Text(
'${description.substring(0, 39)} ...',
textDirection: TextDirection.rtl,
textAlign: TextAlign.justify,
style: TextStyle(color: Colors.black),
),
],
)
],
),
),
),
);
}),
);
}
The problem is in the ListView.itemBuilder on the function _listView. The code below assumes textVal contain both image and data and there should be only one type.
itemBuilder: (context, index) {
var textVal = text_value[index];
String description = textVal['description'];
String id_num = textVal['id_num'];
String id_img = textVal['id_img'];
...
To fix it just default the value to something else if null. It's easy with the null-coalescing operator ??. Take a look:
itemBuilder: (context, index) {
var textVal = text_value[index];
String description = textVal['description'] ?? '';
String id_num = textVal['id_num'] ?? '';
String id_img = textVal['id_img'] ?? '';
...

Does anyone know what's going on with my Listview?

I needed to insert a TextField to search/filter records, but I don't know what's going on.
When I click on the "Cães" option of the BottomNavigationBar, on main.dart,
I only get a CircularProgressIndicator and the data does show up.
Have any of you experienced this problem?
Does anyone know why my Listview doesn't show up?
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:ssk_final/addeditpage.dart';
//import 'package:flutter_localizations/flutter_localizations.dart';
List<dynamic> list = [];
class CaesPage extends StatefulWidget {
// CaesPage({Key key}) : super(key: key);
#override
_CaesPageState createState() => _CaesPageState();
Widget build(BuildContext context) {
return Container(
child: Center(
child: Text("Cadastro de Cães"),
),
);
}
}
class _CaesPageState extends State<CaesPage> {
String searchString = "";
Future<List<Caes>> caes;
Future getData() async {
var url = 'http://.../api2.php?opcao=read';
var response = await http.get(Uri.parse(url));
return json.decode(response.body);
}
/*
Future _showMyDialog(id, nome) async {
return showDialog<void>(
context: context,
barrierDismissible: false, // user must tap button
builder: (BuildContext context) {
return AlertDialog(
title: Text('Exclusão'),
content: SingleChildScrollView(
child: Column(
children: <Widget>[
Text('Confirma a exclusão de ' + nome + '?'),
],
),
),
actions: <Widget>[
TextButton(
child: Text('Confirma'),
onPressed: () {
setState(() {
var url = 'http://.../api.php?opt=delete';
http.post(Uri.parse(url), body: {
'id': id,
});
});
Navigator.pop(context, true);
},
),
TextButton(
child: Text('Cancelar'),
onPressed: () {
Navigator.pop(context);
},
),
],
);
},
);
}
*/
#override
void initState() {
super.initState();
caes = fetchCaes();
}
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
backgroundColor: Color.fromRGBO(1, 87, 155, 1),
focusColor: Colors.blue,
foregroundColor: Colors.white,
hoverColor: Colors.green,
splashColor: Colors.tealAccent,
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => AddEditPage(),
),
);
debugPrint('Clicked FloatingActionButton Button');
},
),
body: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Divider(),
//SizedBox(height: 10),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 15.0),
child: TextField(
onChanged: (value) {
setState(() {
searchString = value.toLowerCase();
});
},
decoration: const InputDecoration(
//contentPadding: EdgeInsets.symmetric(vertical: 10),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.blue, width: 1.0),
borderRadius: BorderRadius.all(Radius.circular(25.0))),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.blue, width: 1.0),
borderRadius: BorderRadius.all(Radius.circular(25.0)),
),
labelText: 'Pesquisa',
suffixIcon: Icon(Icons.search))),
),
SizedBox(height: 10),
Expanded(
child: FutureBuilder<List<Caes>>(
builder: (context, snapshot) {
if (snapshot.hasData) {
return Center(
child: ListView.separated(
padding: const EdgeInsets.all(8),
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
return snapshot.data[index].nome
.toLowerCase()
.contains(searchString)
? Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new InkWell(
onTap: () {
print(index);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => AddEditPage(
caes: snapshot.data,
index: index,
),
),
);
},
child: new Container(
child: Column(
children: [
Text(
(snapshot.data[index].nome),
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold),
),
Text(
('${snapshot.data[index].microchip}'),
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 13,
),
),
Text(
('${snapshot.data[index].pedigree}'),
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 13,
),
),
Text(
(snapshot
.data[index].data_nascimento),
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 13,
),
),
Text(
(snapshot.data[index].sexo),
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 13,
),
),
Text(
(snapshot.data[index].castrado),
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 13,
),
),
],
),
),
),
])
: Container();
},
separatorBuilder: (BuildContext context, int index) {
return snapshot.data[index].nome
.toLowerCase()
.contains(searchString)
? Divider()
: Container();
},
),
);
} else if (snapshot.hasError) {
return Center(child: Text('Error: ${snapshot.error}'));
}
return Center(
child: CircularProgressIndicator(),
);
},
// future: list,
),
),
],
),
);
}
}
class Caes {
final int id;
final String nome;
final int microchip;
final int pedigree;
final String data_nascimento;
final String castrado;
final String sexo;
Caes({
this.id,
this.nome,
this.microchip,
this.pedigree,
this.data_nascimento,
this.castrado,
this.sexo,
});
factory Caes.fromJson(Map<String, dynamic> json) {
return Caes(
id: json['id'],
nome: json['nome'],
microchip: json['microchip'],
pedigree: json['pedigree'],
data_nascimento: json['data_nascimento'],
castrado: json['castrado'],
sexo: json['sexo'],
);
}
}
class Titulos {
Titulos({this.data, this.titulo, this.exposicao});
// non-nullable - assuming the score field is always present
final String data;
final String titulo;
final String exposicao;
factory Titulos.fromJson(Map<String, dynamic> json) {
final data = json['data'] as String;
final titulo = json['titulo'] as String;
final exposicao = json['exposicao'] as String;
return Titulos(data: data, titulo: titulo, exposicao: exposicao);
}
Map<String, dynamic> toJson() {
return {
'data': data,
'titulo': titulo,
'exposicao': exposicao,
};
}
}
Future<List<Caes>> fetchCaes() async {
final response = await http.get(Uri.parse('http://.../api.php?opt=read'));
if (response.statusCode == 200) {
var caesJson = jsonDecode(response.body) as List;
return caesJson.map((caes) => Caes.fromJson(caes)).toList();
} else {
throw Exception('Failed to load Caes');
}
}
Screen
I cant really provide an answer in your list view cause it needs more files to run for me. However I can provide you a nice way to search in a list for items and update it with a text field. You can copy and run the code in the main of a test project to see how it is working.
import 'dart:async';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final StreamController<List<String>> _exercisesStreamController =
StreamController<List<String>>();
late Stream<List<String>> _exercisesStream;
final List<String> _exercises = [
"Running",
"Swimming",
"Football",
"Basketball",
"Volleyball",
"Karate",
"Ski",
"Snowboard",
"Baseball",
"Running1",
"Swimming1",
"Football1",
"Basketball1",
"Volleyball1",
"Karate1",
"Ski1",
"Snowboard1",
"Baseball1",
"Running2",
"Swimming2",
"Football2",
"Basketball2",
"Volleyball2",
"Karate2",
"Ski2",
"Snowboard2",
"Baseball2",
"Running3",
"Swimming3",
"Football3",
"Basketball3",
"Volleyball3",
"Karate3",
"Ski3",
"Snowboard3",
"Baseball3",
];
#override
void initState() {
super.initState();
_exercisesStreamController.sink.add(_exercises);
_exercisesStream = _exercisesStreamController.stream.asBroadcastStream();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(),
body: Padding(
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 10),
child: Column(
children: [
TextFormField(
maxLines: 1,
style: TextStyle(color: Colors.white),
onChanged: (String value) async {
List<String> temp = List.from(_exercises);
temp.removeWhere((element) =>
!element.toLowerCase().contains(value.toLowerCase()));
_exercisesStreamController.sink.add(temp);
},
decoration: InputDecoration(
prefixIcon: Icon(
Icons.search,
color: Colors.white,
),
border: OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(15.0),
),
contentPadding: EdgeInsets.only(left: 15),
filled: true,
fillColor: Colors.blueGrey,
hintText: "search",
hintStyle: TextStyle(
color: Colors.white,
),
),
),
_listViewWidget()
],
),
),
);
}
Widget _listViewWidget() {
return Expanded(
child: StreamBuilder<List<String>>(
initialData: [],
stream: _exercisesStream,
builder: (context, snapshot) {
return ListView.builder(
itemCount: snapshot.data!.length,
itemBuilder: (context, index) {
return Container(
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
color: Colors.blueGrey,
borderRadius: BorderRadius.all(
Radius.circular(15),
),
),
padding: EdgeInsets.all(15),
margin: EdgeInsets.symmetric(vertical: 10),
child: Center(
child: Text(
snapshot.data![index],
style: TextStyle(color: Colors.white),
),
),
);
});
},
),
);
}
}
If you need further instructions i am happy to help.

Unhandled Exception: BlocProvider.of() called with a context that does not contain a SignupBloc

I am a beginner in flutter_bloc library pattern, i am trying to signup http post request. I follow all the bloc necessary steps but when i click on Signup button it shows me on the log "Unhandled Exception:BlocProvider.of() called with a context that does not contain a SignupBloc. No ancestor could be found starting from the context that was passed to BlocProvider.of(). This can happen if the context you used comes from a widget above the BlocProvider." Although i have added this Signupbloc in main.dart how to fix this issue.
Main.dart
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: MultiBlocProvider(providers: [
BlocProvider<RecommendedBloc>(
create: (BuildContext context) => RecommendedBloc(
RecommendedForYouDataService(),
),
),
BlocProvider<CuisineDishesBloc>(
create: (BuildContext context) => CuisineDishesBloc(
BrowseByCuisineDishesDataService(),
),
),
BlocProvider<DetailsBloc>(
create: (BuildContext context) => DetailsBloc(
DetailsDataService(),
),
),
BlocProvider<SearchBloc>(
create: (BuildContext context) => SearchBloc(
AllRestaurantDataService(), SearchRestaurantDataService()),
),
BlocProvider<AllPhotosBloc>(
create: (BuildContext context) =>
AllPhotosBloc(AllPhotosDataService()),
),
BlocProvider<PlacePhotosBloc>(
create: (BuildContext context) =>
PlacePhotosBloc(PlacePhotosDataService()),
),
BlocProvider<FoodPhotosBloc>(
create: (BuildContext context) =>
FoodPhotosBloc(FoodPhotosDataService()),
),
BlocProvider<EventPhotosBloc>(
create: (BuildContext context) =>
EventPhotosBloc(EventPhotosDataService()),
),
BlocProvider<SignupBloc>(
create: (BuildContext context) => SignupBloc(SignUpDataService()),
),
], child: LoginPage()),
);
}
}
SignUpDataService.dart
class SignUpDataService {
Future<SignUp?> makeRequestSignUp(String firstName, String lastName,
String mobileNumber, String password, String gender) async {
var response =
await http.post(Uri.parse('$baseURL/customer/signup'), body: {
"phone_number": mobileNumber,
"password": password,
});
if (response.statusCode == 200) {
final responseString = response.body;
final data = jsonDecode(responseString);
SignUp signUp = SignUp.fromJson(data);
return signUp;
} else {
throw Exception();
}
}
}
Signup_event.dart
#immutable
abstract class SignupEvent {}
class SignUpSubmittedEvent extends SignupEvent {
final String phoneNumber;
final String password;
SignUpSubmittedEvent(this.firstName, this.lastName, this.phoneNumber,
this.password, this.gender);
}
SignupState_state
#immutable
abstract class SignupState {}
class SignupInitialState extends SignupState {}
class SignupLoadingState extends SignupState {}
class SignupSuccessState extends SignupState {
final SignUp data;
SignupSuccessState(this.data);
}
class SignupErrorState extends SignupState {
final String message;
SignupErrorState(this.message);
}
Signup_bloc.dart
class SignupBloc extends Bloc<SignupEvent, SignupState> {
SignUpDataService signUpDataService;
SignupBloc(this.signUpDataService) : super(SignupInitialState());
#override
Stream<SignupState> mapEventToState(
SignupEvent event,
) async* {
if (event is SignUpSubmittedEvent) {
yield SignupLoadingState();
try {
SignUp? signup = await signUpDataService.makeRequestSignUp(
event.phoneNumber,
event.password,
yield SignupSuccessState(signup!);
} catch (e) {
yield SignupErrorState(e.toString());}}}}
Register.dart
class RegisterPage extends StatefulWidget {
const RegisterPage({Key? key}) : super(key: key);
#override
_RegisterPageState createState() => _RegisterPageState();
}
class _RegisterPageState extends State<RegisterPage> {
bool checkOS = Platform.isIOS;
late bool _passwordVisible;
final TextEditingController mobileNumber = TextEditingController();
final TextEditingController password = TextEditingController();
bool _validate = false;
final _formKey = GlobalKey<FormState>();
String pWord = "";
late List<String> menus;
static late int menuIndex;
late SignupBloc signupBloc;
void submitForm() {
final isValid = _formKey.currentState!.validate();
}
#override
void initState() {
_passwordVisible = false;
super.initState();
}
#override
Widget build(BuildContext context) {
var height = MediaQuery.of(context).size.height;
var width = MediaQuery.of(context).size.width;
return Scaffold(
backgroundColor: TuxedoColor.loginColor,
body: Padding(
padding: const EdgeInsets.only(left: 20.0, right: 20.0),
child: Container(
alignment: Alignment.center,
child: Center(
child: Form(
key: _formKey,
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.all(10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
GestureDetector(
onTap: () {
Navigator.pop(context);
},
child: Container(
decoration: BoxDecoration(
border:
Border.all(color: TuxedoColor.greyColor),
borderRadius: BorderRadius.all(Radius.circular(
5.0) // <--- border radius here
),
),
child: Padding(
padding: const EdgeInsets.only(
top: 10.0,
bottom: 10.0,
left: 10.0,
right: 5.0),
child: Icon(
Icons.arrow_back_ios,
color: TuxedoColor.greyColor,
),
),
),
),
Text(
'Sign Up',
style: TextStyle(
fontSize: 25.0, fontWeight: FontWeight.bold),
),
GestureDetector(
onTap: () {},
child: Text(
'عربي',
style: TextStyle(
fontSize: 20.0, fontWeight: FontWeight.bold),
),
)
],
),
),
Padding(
padding: const EdgeInsets.only(
left: 15.0, right: 15.0, top: 35.0),
child: TextFormField(
controller: mobileNumber,
keyboardType: TextInputType.phone,
decoration: new InputDecoration(
fillColor: TuxedoColor.textFieldColor,
filled: true,
hintText: "Mobile Number",
enabledBorder: OutlineInputBorder(
borderSide:
BorderSide(color: TuxedoColor.greyColor)),
focusedBorder: OutlineInputBorder(
borderSide:
BorderSide(color: TuxedoColor.greyColor)),
),
),
),
Padding(
padding: const EdgeInsets.only(
left: 15.0, right: 15.0, top: 30.0),
child: TextFormField(
keyboardType: TextInputType.visiblePassword,
controller: password,
obscureText: !_passwordVisible,
onChanged: (value) => pWord = value,
decoration: new InputDecoration(
suffixIcon: IconButton(
icon: Icon(
_passwordVisible
? Icons.visibility
: Icons.visibility_off,
),
onPressed: () {
setState(() {
_passwordVisible = !_passwordVisible;
});
},
),
fillColor: TuxedoColor.textFieldColor,
filled: true,
hintText: "Password",
enabledBorder: OutlineInputBorder(
borderSide:
BorderSide(color: TuxedoColor.greyColor)),
focusedBorder: OutlineInputBorder(
borderSide:
BorderSide(color: TuxedoColor.greyColor))),
),
),
Padding(
padding: const EdgeInsets.only(
left: 15.0,
right: 15.0,
),
child: ConstrainedBox(
constraints:
BoxConstraints.tightFor(height: height * 0.065),
child: ElevatedButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(
TuxedoColor.redColor),
),
onPressed: () async {
submitForm();
final fName = firstName.text;
final lName = lastName.text;
final mNumber = mobileNumber.text;
final pass = password.text;
final gen = gender.toString();
signupBloc = BlocProvider.of<SignupBloc>(context)
..add(SignUpSubmittedEvent(
mNumber, pass)); //On this line getting error
},
child: Text(
'SignUp',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18.0,
color: TuxedoColor.blackColor),
)),
),
),
],
),
)
],
),
),
),
),
),
),
);
}
}
You should swap MaterialApp and MultiBlocProvider.
Bloc provider must be on top of MaterialApp as suggested in this issue by lib creator Felix.

Getting error while searching documents from cloud firestore

I have stored all articles in cloud firestore and now im searching a article from cloud firestore.
Search is working fine but when i tap on a article to go on detail screen to read more. i m getting this error : type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'DocumentSnapshot'
this is my search screen :
class SearchService {
searchByName(String searchField) {
return FirebaseFirestore.instance
.collection('articles')
.where('searchKey',
isEqualTo: searchField.substring(0, 1).toUpperCase())
.get();
}
}
class SearchScreen extends StatefulWidget {
#override
_SearchScreenState createState() => new _SearchScreenState();
}
class _SearchScreenState extends State<SearchScreen> {
var queryResultSet = [];
var tempSearchStore = [];
initiateSearch(value) {
if (value.length == 0) {
setState(() {
queryResultSet = [];
tempSearchStore = [];
});
}
if (queryResultSet.length == 0 && value.length == 1) {
SearchService().searchByName(value).then((QuerySnapshot docs) {
for (int i = 0; i < docs.docs.length; ++i) {
queryResultSet.add(docs.docs[i].data());
setState(() {
tempSearchStore.add(queryResultSet[i]);
});
}
});
} else {
queryResultSet.forEach((element) {
if (element['title'].toLowerCase().contains(value.toLowerCase()) ==
true) {
if (element['title'].toLowerCase().atIndex(value.toLowerCase()) ==
0) {
setState(() {
tempSearchStore.add(element);
});
}
}
});
}
if (tempSearchStore.length == 0 && value.length > 1) {
setState(() {});
}
}
#override
Widget build(BuildContext context) {
return new Scaffold(
backgroundColor: Colors.white,
appBar: new AppBar(
iconTheme: IconThemeData(color: CustomColors.blackColor),
title: TextField(
onChanged: (val) {
initiateSearch(val);
},
decoration: InputDecoration(
hintText: 'Search here',
hintStyle: TextStyle(
color: CustomColors.greyColor,
fontWeight: FontWeight.bold,
),
border: InputBorder.none,
),
),
),
body: ListView(
padding: EdgeInsets.only(left: 10.0, right: 10.0),
shrinkWrap: true,
children: tempSearchStore.map((element) {
return SearchResults(
data: element,
);
}).toList(),
),
);
}
}
this my search item:
class SearchResults extends StatelessWidget {
final data;
const SearchResults({this.data});
#override
Widget build(BuildContext context) {
var readTime = readingTime(data['desc']);
return InkWell(
onTap: () {
Get.to(
DetailScreen(
articles: data,
),
);
},
child: Container(
height: Get.mediaQuery.size.height * 0.24,
width: Get.mediaQuery.size.width * 0.8,
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 20),
decoration: BoxDecoration(
color: Colors.grey.withOpacity(0.1),
borderRadius: BorderRadius.circular(20),
),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
constraints: BoxConstraints(
maxWidth: Get.mediaQuery.size.width * 0.65,
),
child: Text(
data['title'],
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 22,
color: CustomColors.blackColor,
fontWeight: FontWeight.w600,
),
),
),
Image.network(
data['imageUrl'],
height: 100,
width: 100,
fit: BoxFit.cover,
),
],
),
],
),
),
);
}
}
this is my detail screen to view full article:
class DetailScreen extends StatelessWidget {
final DocumentSnapshot articles;
final ArticlesController articlesController = Get.find<ArticlesController>();
DetailScreen({#required this.articles});
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
backgroundColor: Colors.white,
elevation: 0,
iconTheme: IconThemeData(color: CustomColors.blackColor),
),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.only(top: 40),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
toBeginningOfSentenceCase(
articles.data()['title'],
),
style: TextStyle(
fontSize: 22,
fontWeight: FontWeight.bold,
color: CustomColors.blackColor,
),
),
SizedBox(
height: 10,
),
Padding(
padding: const EdgeInsets.only(
top: 15, right: 30, left: 30, bottom: 15),
child: SelectableText(
articles.data()['desc'],
toolbarOptions: ToolbarOptions(copy: true, selectAll: true),
style: TextStyle(
fontSize: 20,
letterSpacing: 1,
fontWeight: FontWeight.bold,
color: Colors.black,
),
),
),
],
),
),
),
);
}
}
docs.docs[i] is a DocumentSnapshot
But docs.docs[i].data() is a Map<String, dynamic>
You have add lists (queryResultList and other) as Map but detailscreen field is DocumentSnapshot.